package fractal;

import fractal.filter.FractalFilter;
import fractal.fractal.AbsImFractal;
import fractal.fractal.AbsReFractal;
import fractal.fractal.BurningShipFractal;
import fractal.fractal.FourthOddFractal;
import fractal.fractal.Fractal;
import fractal.fractal.FractalData;
import fractal.fractal.MandelFractal;
import fractal.fractal.NewtonFractal;
import fractal.fractal.NewtonFractal2;
import fractal.fractal.OddFractal;
import fractal.fractal.SecondOddFractal;
import fractal.fractal.ThirdOddFractal;
import fractal.res.Resource;
import jinyilw.common.OSTools;
import jinyilw.common.Operator;
import jinyilw.common.SettingTools;
import jinyilw.common.TextTools;
import jinyilw.common.ThreadTools;
import jinyilw.common.ffmpeg.FFmpegTools;
import jinyilw.common.file.FileTools;
import jinyilw.swing.ChooseFileUtils;
import jinyilw.swing.Direction;
import jinyilw.swing.DragCompUtils;
import jinyilw.swing.FontTools;
import jinyilw.swing.SystemTools;
import jinyilw.swing.WindowTools;
import jinyilw.swing.hint.HintWindow;
import jinyilw.swing.i18n.ICSetting;
import jinyilw.swing.i18n.IString;
import jinyilw.swing.i18n.ITexts;
import jinyilw.swing.icon.LazyScaleIcon;
import jinyilw.swing.image.AnimatedGifEncoder;
import jinyilw.swing.image.ImageTools;
import jinyilw.swing.rlaf.UITools;
import jinyilw.swing.rlaf.theme.RRootPaneSet;
import jinyilw.swing.rlaf.theme.UIData;
import jinyilw.swing.rlaf.ui.RRootPaneUI;
import jinyilw.swing.rlaf.utils.RLafUtils;
import jinyilw.swing.visuals.ButtonGroupPanel;
import jinyilw.swing.visuals.CombinedGroupPanel;
import jinyilw.swing.visuals.Icomp.IButton;
import jinyilw.swing.visuals.Icomp.ICheckBox;
import jinyilw.swing.visuals.Icomp.IComboBox;
import jinyilw.swing.visuals.Icomp.IFileChooser;
import jinyilw.swing.visuals.Icomp.ILabel;
import jinyilw.swing.visuals.Icomp.IRadioButton;
import jinyilw.swing.visuals.Icomp.IRichLabel;
import jinyilw.swing.visuals.Icomp.IRichTextLabel;
import jinyilw.swing.visuals.Icomp.ITabbedPane;
import jinyilw.swing.visuals.Jcomp.TransButton;
import jinyilw.swing.visuals.PopWindow;
import jinyilw.swing.visuals.ProgressWindow;
import jinyilw.swing.visuals.Rcomp.RDialog;
import jinyilw.swing.visuals.Rcomp.RFileChooser;
import jinyilw.swing.visuals.Rcomp.RFrame;
import jinyilw.swing.visuals.Rcomp.RMenuLabel;
import jinyilw.swing.visuals.Rcomp.ROptionPane;
import jinyilw.swing.visuals.TextAreaDialog;
import jinyilw.swing.visuals.border.RichTitleBorder;
import jinyilw.swing.visuals.comp.ActScaleImageComp;
import jinyilw.swing.visuals.comp.ColorComp;
import jinyilw.swing.visuals.label.MenuLabel;
import jinyilw.swing.visuals.panel.PalettePanel;
import jinyilw.swing.visuals.window.ITipWindow;
import jinyilw.swing.visuals.window.ScaleSplashWindow;
import jinyilw.tools.video.VideoTools;
import jinyilw.tools.video.jin2mov.DefaultMovieInfoProvider;
import jinyilw.tools.video.jin2mov.FrameSavedListener;
import jinyilw.tools.video.jin2mov.Jim2Mov;
import jinyilw.tools.video.jin2mov.MovieInfoProvider;
import jinyilw.tools.video.jin2mov.MovieSaveException;
import jinyilw.tools.video.jin2mov.MovieUtils;

import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.RootPaneUI;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serial;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class FractalFrame extends RFrame
{
	@Serial
	private static final long serialVersionUID = -7616451838719573009L;
	static ScaleSplashWindow launchW;
	public static final int oldVERSION = 5;
	public static final int VERSION = 6;
	public static final String TITLE = "神奇的世界-分形6.1";
	static final String exTITLE = TITLE + "_展开放大";
	static final String TITLE_EN = "The magic world-fractal 6.1";
	static final String exTITLE_EN = TITLE_EN + "_expand";
	// 分形
	private static final Fractal[] fractalArr = {new MandelFractal(),
			new OddFractal(), new AbsReFractal(), new AbsImFractal(),
			new BurningShipFractal(), new NewtonFractal2(),
			new SecondOddFractal(), new ThirdOddFractal(),
			new FourthOddFractal(), new NewtonFractal()};
	int fractalID = 5;
	Fractal fractal = fractalArr[fractalID];
	ICSetting[] ititles = {
			new ICSetting("title1", exTITLE + "_布罗特分形",
					exTITLE_EN + "_Mandebort"),
			new ICSetting("title2", exTITLE + "_分形1", exTITLE_EN + "_Fractal1"),
			new ICSetting("title3", exTITLE + "_分形2", exTITLE_EN + "_Fractal2"),
			new ICSetting("title4", exTITLE + "_分形3", exTITLE_EN + "_Fractal3"),
			new ICSetting("title5", exTITLE + "_火烧船分形",
					exTITLE_EN + "_Burning Ship"),
			new ICSetting("title6", exTITLE + "_牛顿分形", exTITLE_EN + "_Newton"),
			new ICSetting("title7", exTITLE + "_分形4", exTITLE_EN + "_Fractal4"),
			new ICSetting("title8", exTITLE + "_分形5", exTITLE_EN + "_Fractal5"),
			new ICSetting("title9", exTITLE + "_分形6",
					exTITLE_EN + "_Fractal6")};

	int filterID = 0;
	FractalFilter filter = FractalFilter.filterArr[filterID];

	// 面板大小
	public static final int MW = 500, MH = 420;
	// 参数因子
	int gS = 1;
	double zoomFactor = 3, rS = 0.5;

	final int originalBackPix = new Color(204, 255, 255).getRGB();
	int colorType = 2;
	int[] colorMatchSpace;
	ColorMap colorMap = new ColorMap();
	Color[] gradualColors = new Color[4];
	int[] gradualColorRGBs = {-205, -39220, -16711681, -10066177};
	ColorComp graColorLabel;

	int[] pixels, recordN;
	BufferedImage fraImage, logo;
	int logoWidth = 20, logoHeight = 10;
	Point location = new Point();
	// 动画
	FractalData[] zoomDatas = new FractalData[2];
	ArrayList<FractalData> customDatas = new ArrayList<>();
	ArrayList<FractalData> gifDatas = new ArrayList<>();
	ArrayList<FractalData> allDatas = new ArrayList<>();
	int animateID = 1;
	int sfFrame = 0;
	int kFC = 0;
	int fC = 1;
	int aniN = 200;
	int[] aniNBK = new int[30];
	boolean[] bools = new boolean[4];
	long ct1 = 0, ct2 = 0, sT, aT = 80;
	int gifN = 0, gifF = 0;
	// 初始化
	boolean showInfo = true, firstOpen = true, s1 = true, s2 = true, s3 = true,
			s4 = true, sM = true;
	int core = 4;
	// 保存
	int saveW = 960, saveH = 600, dX = 0, dY = 0, dW = MW, dH = MH;
	double logoRatio;
	int logoX, logoY, logoW, logoH;
	private final static float[] frameRates = {25, 29.7f, 20, 26, 27, 28, 29,
			30, 10, 50, 60, 80};
	private float frameRate = 30;
	// 线程
	volatile boolean tG = false;

	// GUI
	DrawPanel drawPanel;
	IRadioButton rCR, mCR = new IRadioButton();
	JComboBox sizeBox, colorTypeBox;
	JComboBox aSC, fraC;
	SpinnerNumberModel maxNSNM, sfSNM, rotateSNM, growSNM, R_SNM, nbkSNM;
	ILabel xzLabel, szLabel;
	JSpinner mNS, rSp;
	IButton grow, dis;

	IButton backwardB, forwardB;
	JTextField wT, hT;
	ICheckBox moC;
	IButton sAB, aMB, rB;
	ILabel asL;
	JTextField sfT, sfT2;
	JComboBox fpsBox;
	IButton zOB, zIB, zOAB, zIAB;
	IButton sfB, sfmB;
	ButtonGroupPanel coreGroup;
	TransButton abB, clearB;
	IButton hB, saveAB;

	IButton preGifB, saveGifB;
	ILabel gifFL;

	PalettePanel palette;
	ICheckBox infoCheckBox;
	IButton deB;

	CombinedGroupPanel fractalGroup, filterGroup;
	ICheckBox checkBox1, checkBox2, checkBox3, checkBox4;
	RDialog tzDialog, kzDialog, szDialog, dhDialog;
	GradientColorDialog gradientColorDialog;
	TextAreaDialog helpDialog;
	AboutDialog aboutDialog;
	ITabbedPane tabbedPane;
	int EDNum = 5, diaNumber = 0;
	EnlargeDialog[] largeDialogs = new EnlargeDialog[EDNum];
	ITipWindow tipWindow;
	PopWindow videoPopWindow;
	File videoFile;
	PopWindow picturePopWindow;
	File pictureFile;
	PopWindow folderPopWindow;
	String folderDirectory;
	ProgressWindow progressWindow;
	HelpWindow helpWindow;

	public static void main(String[] args)
	{
		if (OSTools.isMac())
		{
			launchW = new ScaleSplashWindow(
					Resource.class.getResource("launch.png"));
			launchW.customLaunch();
			// launchW.launch();
		}
		EventQueue.invokeLater(() -> {
			try
			{
				new FractalFrame();
			} catch (Exception e)
			{
				e.printStackTrace();
			}
		});
	}

	public FractalFrame()
	{
		initFractal();
		// format.setMaximumFractionDigits(15);
		setIconImage(Resource.getBufferedImage("icon.png"));
		logo = Resource.getBufferedImage("logo.png");
		if (logo != null)
		{
			logoWidth = logo.getWidth(null);
			logoHeight = logo.getHeight(null);
		}
		changeSize(saveW, saveH);
		initGUI();
		if (fractalID == 5)
			chooseNewton();
		setVisible(true);
		progressWindow = new ProgressWindow();
		progressWindow.setCancelText(new ICSetting("cancel", "取 消", "cancel"));
		progressWindow.addCancelOperator(o -> {
			if (currentJim2Mov != null)
				currentJim2Mov.forceStop();
		});
	}

	private void setBackPicture(BufferedImage bfg)
	{
		if (bfg == null)
			return;
		if (bfg.getWidth() < 1000 || bfg.getHeight() < 860)
			bfg = ImageTools.getShapedImage(bfg, 1000, 860);
		setCustomBGImage(bfg.getSubimage(145, 95, 643, 496));
		tzDialog.setCustomBGImage(bfg.getSubimage(155, 0, 740, 90));
		kzDialog.setCustomBGImage(bfg.getSubimage(0, 30, 140, 560));
		dhDialog.setCustomBGImage(bfg.getSubimage(0, 595, 940, 120));
		szDialog.setCustomBGImage(bfg.getSubimage(793, 105, 140, 485));
	}

	protected void lightItemAction()
	{
		tG = false;
		UITools.setLightTheme();
		setBackPicture((BufferedImage) UITools.lightImage);
	}

	protected void darkItemAction()
	{
		tG = false;
		UITools.setDarkTheme();
		setBackPicture((BufferedImage) UITools.darkImage);
	}

	protected void blackItemAction()
	{
		tG = false;
		UITools.setBlackTheme();
		setBackPicture((BufferedImage) UITools.blackImage);
	}

	IString title = new IString("setBack.choose", "背景设置-选择图片文件",
			"Set background - choose picture");

	protected void openBackItemAction()
	{
		tG = false;
		RFileChooser chooser = ImageTools.getPictureOpenChooser("bgImages",
				title.getI18nString());
		File imgFile = chooser.openAndGetOpenFile(this);
		if (imgFile == null)
			return;
		UITools.setBGImageFile(imgFile);
		setBackPicture((BufferedImage) RRootPaneSet.getRootPaneSet().bgImage);
	}

	protected void resetBackItemAction()
	{
		UITools.resetBGImage();
		setBackPicture((BufferedImage) RRootPaneSet.getRootPaneSet().bgImage);
	}

	ICSetting[] iTipStr = {
			new ICSetting("tipStr1", "用鼠标左键向右拖动放大分形！",
					"Left-button drag to zoom in！"),
			new ICSetting("tipStr2", "用鼠标右键拖动移动分形！",
					"Right-button drag to move！"),
			new ICSetting("tipStr3", "拖动四周边框可调整分形大小！",
					"Drag frame border to resize！"),
			new ICSetting("tipStr4", "取消'展开时显示'可不再显示提示",
					"Uncheck 'show when open' to cancel"),
			new ICSetting("tipStr5", "左键向左拖动或按键盘'<'键后退！",
					"Press '<' key to backward!"),
			new ICSetting("tipStr6", "右键单击或按键盘'>'键前进！",
					"Press '>' key to forward!"),
			new ICSetting("tipStr7", "按键盘方向键也可移动分形！",
					"Press direction keys to move!"),
			new ICSetting("tipStr8", "按键盘'W'键连续上移！",
					"Press 'W' key to continuous move up!"),
			new ICSetting("tipStr9", "左键单击或按空格键可停止！",
					"Press left-button or space can stop!"),
			new ICSetting("tipStr10", "按键盘'S'键连续下移！",
					"Press 'S' key to continuous move down!"),
			new ICSetting("tipStr11", "按键盘'A'键连续左移！",
					"Press 'A' key to continuous move left!"),
			new ICSetting("tipStr12", "按键盘'D'键连续右移！",
					"Press 'D' key to continuous move right!"),
			new ICSetting("tipStr13", "长按左键可放大此位置分形！",
					"Hold left-button to zoom-in the location"),
			new ICSetting("tipStr14", "长按右键可缩小此位置分形！",
					"Hold right-button to zoom-out the location"),
			new ICSetting("tipStr15", "按键盘'F1'键可使分形生长！",
					"Press 'F1' key to grow fractal!"),
			new ICSetting("tipStr16", "按键盘'F2'键可使分形消除！",
					"Press 'F2' key to shrink fractal!"),
			new ICSetting("tipStr17", "按键盘'F3'键可连续放大分形！",
					"Press 'F3' key to continuous zoom in"),
			new ICSetting("tipStr18", "按键盘'F4'键可连续缩小分形！",
					"Press 'F4' key to continuous zoom out")};
	private void initFractal()
	{
		largeDialogs[0] = new EnlargeDialog(this);
		tipWindow = new ITipWindow(iTipStr, largeDialogs[0]);
		showInfo = (Boolean) SettingTools.getDefaultSettingData("showInfo",
				true);
		core = (Integer) SettingTools.getDefaultSettingData("core",
				ThreadTools.maxCore);

		pixels = new int[MW * MH];
		recordN = new int[MW * MH];
		int pix = (Integer) SettingTools.getDefaultSettingData("bPix",
				originalBackPix);
		filterID = (Integer) SettingTools.getDefaultSettingData("filterID",
				filterID);
		filter = FractalFilter.filterArr[filterID];
		for (int i = 0; i < fractalArr.length; i++)
		{
			fractalArr[i].setId(i);
			fractalArr[i].setSize(MW, MH);
			fractalArr[i].setFractalPNData(pixels, recordN);
			fractalArr[i].setColorMap(colorMap);
			fractalArr[i].setBackColorPix(pix);
			fractalArr[i].setFilter(filter);
		}
		fractalID = (Integer) SettingTools.getDefaultSettingData("fractalID",
				fractalID);
		fractal = fractalArr[fractalID];
		fractal.initialise();
		fractal.getCustomData();

		saveW = (Integer) SettingTools.getDefaultSettingData("saveW", saveW);
		saveH = (Integer) SettingTools.getDefaultSettingData("saveH", saveH);
		colorType = (Integer) SettingTools.getDefaultSettingData("colorType",
				colorType);
		for (int i = 0; i < gradualColors.length; i++)
			gradualColors[i] = new Color(
					(Integer) SettingTools.getDefaultSettingData(
							"gradualColors" + i, gradualColorRGBs[i]));
		colorMap.getCustomData();
		setColorMatchSpace(colorType, false);
		fractal.initRecordData();
		openLargePanel();

		firstOpen = false;
		tipWindow.addFinishActionListener(e -> {
			tipWindow.dispose();
			showInfo = false;
			infoCheckBox.setSelected(showInfo);
		});
	}

	private void initGUI()
	{
		setTitle(new ICSetting("appTitle", TITLE, TITLE_EN));
		setSize(643, 496);
		setResizable(false);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		JPanel contentPanel = new JPanel();
		setContentPane(contentPanel);
		contentPanel.setLayout(null);
		addComponentListener(new ThisComponentListener());
		addBeforeClosingOperator(new BeforeClosingOperator());
		addClosingOperator(new ClosingOperator());
		addHideOperator(o -> tG = false);
		drawPanel = new DrawPanel();
		SystemTools.makeDropTarget(drawPanel, o -> {
			if (o instanceof List)
			{
				File f = (File) ((List<?>) o).get(0);
				if (f != null && f.isFile() && f.getName().endsWith(".fra"))
					openFraFile(f);
			}
		});
		contentPanel.add(drawPanel);
		drawPanel.setBounds(8, 8, MW, MH);
		s1 = (Boolean) SettingTools.getDefaultSettingData("s1", s1);
		s2 = (Boolean) SettingTools.getDefaultSettingData("s2", s2);
		s3 = (Boolean) SettingTools.getDefaultSettingData("s3", s3);
		s4 = (Boolean) SettingTools.getDefaultSettingData("s4", s4);
		sM = (Boolean) SettingTools.getDefaultSettingData("sM", sM);
		initTZDialog();
		initKZDialog();
		initDHDialog();
		resetDHDialog();
		initSZDialog();
		tzDialog.setTitle(new ICSetting("Adjustment", "调 整", "Adjustment"));
		kzDialog.setTitle(new ICSetting("Control", "控 制", "Control"));
		dhDialog.setTitle(new ICSetting("Animation", "    动 画",
				"                      Animation"));
		szDialog.setTitle(new ICSetting("Setting", "设 置", "Setting"));

		palette = new PalettePanel();
		contentPanel.add(palette);
		palette.setBounds(520, 5, 110, 135);

		palette.setBorder(
				new RichTitleBorder(Resource.getLazyScaleIcon("color3.png"),
						new ICSetting("palette", "调色板", "Palette")));

		clearB = new TransButton(
				new ICSetting("clearColor", "清除调色", "Clear all"));
		contentPanel.add(clearB);
		clearB.addMouseListener(new ClearBActionListener());
		clearB.setBounds(525, 140, 102, 26);

		fractalGroup = new CombinedGroupPanel();
		contentPanel.add(fractalGroup);
		fractalGroup.setLayout(null);
		fractalGroup.setBounds(520, 168, 110, 137);
		fractalGroup.setBorder(
				new RichTitleBorder(Resource.getLazyScaleIcon("fractal2.png"),
						new ICSetting("fractalGroup", "分形选择", "Fractals")));

		IRadioButton[] fractalRadios = new IRadioButton[6];
		for (int i = 0; i < fractalRadios.length; i++)
		{
			fractalRadios[i] = new IRadioButton();
			fractalRadios[i].setBounds(10, 23 + i * 15, 110, 18);
		}
		fractalGroup.add(fractalRadios[0]);
		fractalGroup.add(fractalRadios[3]);
		fractalGroup.add(fractalRadios[4]);
		fractalGroup.add(fractalRadios[5]);
		fractalGroup.add(fractalRadios[1]);
		fractalGroup.add(fractalRadios[2]);
		fractalRadios[0].setText(
				new ICSetting("mandelbrot", "布罗特分形", "Mandelbrot"), true);
		fractalRadios[1].setText(
				new ICSetting("burningShip", "火烧船分形", "Burning Ship"), true);
		fractalRadios[2].setText(new ICSetting("newton", "牛顿分形", "Newton"));
		fractalRadios[3].setText(new ICSetting("fractal1", "分形1", "Fractal1"));
		fractalRadios[4].setText(new ICSetting("fractal2", "分形2", "Fractal2"));
		fractalRadios[5].setText(new ICSetting("fractal3", "分形3", "Fractal3"));

		ArrayList<IString> fractalIStrings = IString.createArray("fractal",
				"  分形", "  Fractal", 4, 7);
		fractalIStrings.add(0,
				new IString("moreFractal", " 更多分形", "  More..."));
		JComboBox comboBox2 = new JComboBox(fractalIStrings.toArray());
		fractalGroup.setComboBox(comboBox2, true);
		comboBox2.setBounds(10, 113, 92, 20);

		fractalGroup.addActionListener(new FractalGroupActionListener());
		fractalGroup.setSelectedIndex(fractalID);

		filterGroup = new CombinedGroupPanel();
		contentPanel.add(filterGroup);
		filterGroup.setLayout(null);
		filterGroup.setBounds(520, 307, 110, 96);
		filterGroup.setBorder(
				new RichTitleBorder(Resource.getLazyScaleIcon("filter.png"),
						new ICSetting("filterGroup", "滤镜选择", "Filters")));

		IRadioButton[] filterRadios = new IRadioButton[3];
		ArrayList<ICSetting> filterISettings = ICSetting.createArray("filter",
				"滤镜", "Filter", 1, 3);
		for (int i = 0; i < filterRadios.length; i++)
		{
			filterRadios[i] = new IRadioButton();
			filterGroup.add(filterRadios[i]);
			filterRadios[i].setBounds(10, 23 + i * 16, 70, 18);
			filterRadios[i].setText(filterISettings.get(i));
		}

		ArrayList<IString> filterIStrings = IString.createArray("filter",
				"  滤镜", "  Filter", 4, 8);
		filterIStrings.add(0, new IString("more", " 更多滤镜", "  More..."));
		filterIStrings.add(new IString("noneFilter", "  无滤镜", "  None"));
		JComboBox comboBox = new JComboBox(filterIStrings.toArray());
		filterGroup.setComboBox(comboBox, true);
		comboBox.setBounds(10, 70, 85, 20);
		filterGroup.addActionListener(new FilterGroupActionListener());
		filterGroup.setSelectedIndex(filterID);

		IButton exButton = new IButton();
		contentPanel.add(exButton);
		exButton.setFont(FontTools.getCustomFont(15));
		exButton.setBackground(new Color(230, 0, 0));
		exButton.setForeground(Color.WHITE);
		exButton.addActionListener(new ExpandButtonActionListener());
		exButton.setText(new ICSetting("expand", "展开放大", "Expand"));
		exButton.setDefaultAlpha(0.8f);
		exButton.setHoverAlpha(1);
		exButton.setBounds(520, 405, 110, 32);
		setCustomMenuBar(createMenu());
		setBackPicture((BufferedImage) RRootPaneSet.getRootPaneSet().bgImage);
	}

	private Container createMenu()
	{
		Container menu = new Container();
		menu.setSize(getWidth(), 26);
		menu.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
		checkBox1 = new ICheckBox();
		menu.add(checkBox1);
		checkBox1.addActionListener(new WcheckBox1ActionListener());
		checkBox1.setText(new ICSetting("adjustment", "调整", "Adjustment"),
				true);
		checkBox1.setSelected(s1);
		checkBox2 = new ICheckBox();
		menu.add(checkBox2);
		checkBox2.addActionListener(new WcheckBox2ActionListener());
		checkBox2.setText(new ICSetting("control", "控制", "Control"), true);
		checkBox2.setSelected(s2);
		checkBox3 = new ICheckBox();
		menu.add(checkBox3);
		checkBox3.addActionListener(new WcheckBox3ActionListener());
		checkBox3.setText(new ICSetting("animation", "动画", "Animation"), true);
		checkBox3.setSelected(s3);
		checkBox4 = new ICheckBox();
		menu.add(checkBox4);
		checkBox4.addActionListener(new WcheckBox4ActionListener());
		checkBox4.setText(new ICSetting("setting", "设置", "Setting"), true);
		checkBox4.setSelected(s4);

		JLabel secion1 = new JLabel(" | ");
		secion1.setForeground(Color.white);
		menu.add(secion1);
		RMenuLabel setBG = new RMenuLabel();
		// setBG.setToolTipText("选取图片文件设置成窗体背景");
		setBG.setForeground(Color.YELLOW);
		setBG.setSize(80, 25);
		// setBG.setText("设置背景");
		setBG.setText(new ICSetting("setBG", "设置背景", "SetBG"));
		Operator oOperator = (Object o) ->
		{
			openBackItemAction();
		};
		Operator rOperator = (Object o) ->
		{
			resetBackItemAction();
		};
		setBG.setClickOperator(oOperator);
		menu.add(setBG);
		JLabel secion2 = new JLabel(" | ");
		secion2.setForeground(Color.white);
		menu.add(secion2);
		RMenuLabel setLight = new RMenuLabel();
		// setLight.setToolTipText("设置浅色主题");
		setLight.setForeground(Color.green);
		setLight.setSize(25, 25);
		setLight.setText(new ICSetting("mlight", "浅色主题", "Light"));
		Operator lOperator = (Object o) ->
		{
			lightItemAction();
		};
		setLight.setClickOperator(lOperator);
		menu.add(setLight);
		RMenuLabel setDark = new RMenuLabel();
		// setDark.setToolTipText("设置深色主题");
		setDark.setForeground(Color.PINK);
		setDark.setSize(25, 25);
		setDark.setText(new ICSetting("mdark", "深色主题", "Dark"));
		Operator dOperator = (Object o) ->
		{
			darkItemAction();
		};
		setDark.setClickOperator(dOperator);
		menu.add(setDark);
		MenuLabel setBlack = new MenuLabel();
		// setBlack.setToolTipText("设置黑色主题");
		setBlack.setForeground(new Color(100, 100, 250));
		setBlack.setSize(25, 25);
		setBlack.setText(new ICSetting("mblack", "黑色主题", "Black"));
		Operator<MouseEvent> bOperator = o ->
		{
			blackItemAction();
		};
		setBlack.setClickOperator(bOperator);
		menu.add(setBlack);
		RLafUtils.configSettingOperator(lOperator, dOperator, bOperator,
				oOperator, rOperator);
		RLafUtils.configBlurSliderOperator((Object o) ->
		{
			setBackPicture(
					(BufferedImage) RRootPaneSet.getRootPaneSet().bgImage);
		});
		return menu;
	}

	private void initTZDialog()
	{
		tzDialog = new RDialog(this);
		tzDialog.addClosingOperator(o -> {
			checkBox1.setSelected(false);
			s1 = false;
		});
		tzDialog.setSize(740, 90);
		tzDialog.setResizable(false);
		Container tzPanel = tzDialog.getContentPane();
		tzPanel.setLayout(null);
		backwardB = new IButton();
		tzPanel.add(backwardB);
		backwardB.setBackground(new Color(100, 255, 47));
		backwardB.addActionListener(new BackwardActionListener());
		backwardB.setText(new ICSetting("backward", "后退 %d", "Backward %d",
				backwardB, 2));
		backwardB.setBounds(10, 5, 65, 23);
		forwardB = new IButton();
		tzPanel.add(forwardB);
		forwardB.setBackground(new Color(100, 255, 47));
		forwardB.addActionListener(new ForwardActionListener());
		forwardB.setText(
				new ICSetting("forward", "前进 %d", "Forward %d", forwardB, 2));
		forwardB.setBounds(80, 5, 65, 23);
		backwardB.setReplaceData(0);
		forwardB.setReplaceData(0);

		IButton initB = new IButton();
		initB.setBounds(160, 5, 119, 23);
		tzPanel.add(initB);
		initB.addActionListener(new InitFraActionListener());
		initB.setBackground(new Color(0, 191, 255));
		initB.setText(new ICSetting("initialize", "初始化分形", "Initialize"));
		IButton sJB = new IButton();
		tzPanel.add(sJB);
		sJB.setBackground(new Color(255, 102, 51));
		sJB.addActionListener(new SavePictureActionListener());
		sJB.setDefaultAlpha(0.8f);
		sJB.setHoverAlpha(1);
		sJB.setText(new ICSetting("savePicture", "保 存 图 片", "Save picture"));
		sJB.setBounds(605, 5, 119, 23);

		IButton fra2png = new IButton();
		tzPanel.add(fra2png);
		fra2png.setBackground(makeColor);
		fra2png.addActionListener(new FraToPngActionListener());
		fra2png.setText(new ICSetting("fraToPng", "fra批量转png", "fra to png"));
		fra2png.setBounds(605, 35, 119, 23);

		IString[] iStrings = new IString[]{
				new IString("customSize", "自定义图片/视频大小", "Customize size"),
				new IString("preSize1", "保存为512×288", "Save as 512×288"),
				new IString("preSize2", "保存为640×360", "Save as 640×360"),
				new IString("preSize3", "保存为360×640", "Save as 360×640"),
				new IString("preSize4", "保存为720×480", "Save as 720×480"),
				new IString("preSize5", "保存为480×720", "Save as 480×720"),
				new IString("preSize6", "保存为800×450", "Save as 800×450"),
				new IString("preSize7", "保存为450×800", "Save as 450×800"),
				new IString("preSize8", "保存为960×540", "Save as 960×540"),
				new IString("preSize9", "保存为540×960", "Save as 540×960"),
				new IString("preSize10", "保存为1024×576", "Save as 1024×576"),
				new IString("preSize11", "保存为576×1024", "Save as 576×1024"),
				new IString("preSize12", "保存为1280×720", "Save as 1280×720"),
				new IString("preSize13", "保存为720×1280", "Save as 720×1280"),
				new IString("preSize14", "保存为1366×768", "Save as 1366×768"),
				new IString("preSize15", "保存为1600×900", "Save as 1600×900"),
				new IString("preSize16", "保存为1920×1080", "Save as 1920×1080")};
		sizeBox = new IComboBox(iStrings);
		tzPanel.add(sizeBox);
		sizeBox.addActionListener(e -> {
			switch (sizeBox.getSelectedIndex())
			{
				case 1:
					changeSizeAct(512, 288);
					break;
				case 2:
					changeSizeAct(640, 360);
					break;
				case 3:
					changeSizeAct(360, 640);
					break;
				case 4:
					changeSizeAct(720, 480);
					break;
				case 5:
					changeSizeAct(480, 720);
					break;
				case 6:
					changeSizeAct(800, 450);
					break;
				case 7:
					changeSizeAct(450, 800);
					break;
				case 8:
					changeSizeAct(960, 540);
					break;
				case 9:
					changeSizeAct(540, 960);
					break;
				case 10:
					changeSizeAct(1024, 576);
					break;
				case 11:
					changeSizeAct(576, 1024);
					break;
				case 12:
					changeSizeAct(1280, 720);
					break;
				case 13:
					changeSizeAct(720, 1280);
					break;
				case 14:
					changeSizeAct(1366, 768);
					break;
				case 15:
					changeSizeAct(1600, 900);
					break;
				case 16:
					changeSizeAct(1920, 1080);
			}
		});
		sizeBox.setBounds(315, 5, 150, 22);
		sizeBox.setSelectedIndex(0);
		// new String[] { " 正常颜色", " 渐变颜色", " 全彩颜色" }
		colorTypeBox = new IComboBox(new IString[]{
				new IString("standardColor", "  正常颜色", "standard color"),
				new IString("gradientColor", "  渐变颜色", "gradient color"),
				new IString("fullColor", "  全彩颜色", "full color")});
		tzPanel.add(colorTypeBox);
		colorTypeBox.setSelectedIndex(colorType);
		colorTypeBox.addActionListener(new ColorModelBoxActionListener());
		colorTypeBox.setBounds(15, 37, 125, 22);

		graColorLabel = new ColorComp(gradualColors);
		tzPanel.add(graColorLabel);
		graColorLabel.setBounds(155, 38, 130, 18);
		graColorLabel.addMouseListener(new MouseAdapter()
		{
			@Override
			public void mouseClicked(final MouseEvent e)
			{
				if (!graColorLabel.isEnabled())
					return;
				eOT();
				if (gradientColorDialog == null)
					createGradientColorDialog();
				if (gradientColorDialog.isVisible())
					gradientColorDialog.dispose();
				else
				{
					gradientColorDialog.update();
					gradientColorDialog.setLocation(tzDialog.getX() + 135,
							tzDialog.getY() + 80);
					gradientColorDialog.setVisible(true);
				}
			}
		});
		xzLabel = new ILabel();
		tzPanel.add(xzLabel);
		xzLabel.setText(new ICSetting("limitParameter", "限制参数",
				"limitParameter", xzLabel, 2));
		xzLabel.setHorizontalAlignment(JLabel.RIGHT);
		xzLabel.setBounds(305, 37, 78, 18);
		R_SNM = new SpinnerNumberModel(fractal.getR(), 0, 20, 0.01);
		rSp = new JSpinner(R_SNM);
		tzPanel.add(rSp);
		rSp.addChangeListener(new RSpinnerChangeListener());
		rSp.setBounds(385, 35, 58, 20);
		szLabel = new ILabel();
		tzPanel.add(szLabel);
		szLabel.setText(new ICSetting("growParameter", "生长参数", "growParameter",
				szLabel, 2));
		szLabel.setHorizontalAlignment(JLabel.RIGHT);
		szLabel.setBounds(440, 37, 88, 18);
		maxNSNM = new SpinnerNumberModel(fractal.getMaxN(), 10, 2000, gS);
		mNS = new JSpinner(maxNSNM);
		tzPanel.add(mNS);
		mNS.addChangeListener(new MaxNspinnerChangeListener());
		mNS.setBounds(530, 35, 65, 20);
		WHChangeActionListener whChangeListener = new WHChangeActionListener();

		wT = new JTextField();
		tzPanel.add(wT);
		wT.addActionListener(whChangeListener);
		wT.setText(String.valueOf(saveW));
		wT.setBounds(476, 5, 50, 21);
		wT.setHorizontalAlignment(JTextField.CENTER);
		JLabel lX = new JLabel();
		tzPanel.add(lX);
		lX.setText("×");
		lX.setBounds(530, 6, 13, 16);

		hT = new JTextField();
		tzPanel.add(hT);
		hT.addActionListener(whChangeListener);
		hT.setText(String.valueOf(saveH));
		hT.setBounds(543, 5, 50, 21);
		hT.setHorizontalAlignment(JTextField.CENTER);
	}

	private void initKZDialog()
	{
		kzDialog = new RDialog(this);
		kzDialog.addClosingOperator(o -> {
			checkBox2.setSelected(false);
			s2 = false;
		});
		kzDialog.setSize(140, 560);
		kzDialog.setResizable(false);
		Container kzPanel = kzDialog.getContentPane();
		kzPanel.setLayout(null);
		moC = new ICheckBox();
		kzPanel.add(moC);
		moC.setSelected(true);
		moC.setText(new ICSetting("rightToMove", "右键拖动移动", "useRightToMove",
				moC, 2));
		moC.setBounds(15, 53, 110, 18);

		mCR.setBounds(15, 24, 110, 23);
		kzPanel.add(mCR);
		ButtonGroup b1 = new ButtonGroup();
		b1.add(mCR);

		mCR.setText(
				new ICSetting("leftToMove", "左键拖动移动", "useLeftToMove", mCR, 2));
		rCR = new IRadioButton();
		rCR.setBounds(15, 5, 110, 23);
		kzPanel.add(rCR);
		b1.add(rCR);
		rCR.setSelected(true);
		rCR.setText(
				new ICSetting("leftToZoom", "左键拖动放大", "useLeftToZoom", rCR, 2));
		ILabel sFL = new ILabel();
		kzPanel.add(sFL);
		sFL.setText(
				new ICSetting("zoomFactor", " 缩放因子", "zoomFactor ", sFL, 3));
		sFL.setHorizontalAlignment(JLabel.CENTER);
		sFL.setBounds(10, 90, 60, 18);
		sfSNM = new SpinnerNumberModel(zoomFactor, 0, 50, 0.1);
		JSpinner sFS = new JSpinner(sfSNM);
		kzPanel.add(sFS);
		sFS.addChangeListener(new SFspinnerChangeListener());
		sFS.setBounds(71, 88, 52, 20);
		ILabel mL = new ILabel();
		kzPanel.add(mL);
		mL.setText(
				new ICSetting("rotateFactor", " 旋转因子", "rotateFactor", mL, 3));
		mL.setHorizontalAlignment(JLabel.CENTER);
		mL.setBounds(10, 113, 60, 18);
		rotateSNM = new SpinnerNumberModel(rS, 0.25, 50, 0.25);
		JSpinner rotateS = new JSpinner(rotateSNM);
		kzPanel.add(rotateS);
		rotateS.addChangeListener(new RotateSpinnerChangeListener());
		rotateS.setBounds(71, 111, 52, 20);
		ILabel gL = new ILabel();
		kzPanel.add(gL);
		gL.setText(new ICSetting("growFactor", " 生长因子", "growFactor  ", gL, 3));
		gL.setHorizontalAlignment(JLabel.CENTER);
		gL.setBounds(10, 137, 60, 18);
		growSNM = new SpinnerNumberModel(gS, 1, 100, 1);
		JSpinner grS = new JSpinner(growSNM);
		kzPanel.add(grS);
		grS.addChangeListener(new GrowSpinnerChangeListener());
		grS.setBounds(71, 135, 52, 20);

		IButton laB = new IButton();
		kzPanel.add(laB);
		laB.addActionListener(new LargerButtonActionListener());
		laB.setText(new ICSetting("zoomIn", "放大", "Zoom-in"), true);
		laB.setBounds(20, 170, 102, 23);
		IButton smB = new IButton();
		kzPanel.add(smB);
		smB.addActionListener(new SmallerButtonActionListener());
		smB.setText(new ICSetting("zoomOut", "缩小", "Zoom-out"), true);
		smB.setBounds(20, 195, 102, 23);
		IButton cLB = new IButton();
		kzPanel.add(cLB);
		cLB.addActionListener(new CLargerButtonActionListener());
		cLB.setText(
				new ICSetting("continuousIn", "连续放大", "Continuous-in", cLB, 2));
		cLB.setBounds(20, 220, 102, 23);
		IButton cSB = new IButton();
		kzPanel.add(cSB);
		cSB.addActionListener(new CSmallerButtonActionListener());
		cSB.setText(new ICSetting("continuousOut", "连续缩小", "Continuous-out",
				cSB, 2));
		cSB.setBounds(20, 245, 102, 23);

		IButton clock = new IButton();
		kzPanel.add(clock);
		clock.addActionListener(new ClockButtonActionListener());
		clock.setText(new ICSetting("clockwise", "顺时针旋转", "Clockwise rotate",
				clock, 2));
		clock.setBounds(20, 285, 102, 23);
		IButton unClock = new IButton();
		kzPanel.add(unClock);
		unClock.addActionListener(new UnclockButtonActionListener());
		unClock.setText(new ICSetting("counterclockwise", "逆时针旋转",
				"Counterclockwise", unClock, 2));
		unClock.setBounds(20, 310, 102, 23);

		IButton xClock = new IButton();
		kzPanel.add(xClock);
		xClock.addActionListener(new XclockButtonActionListener());
		xClock.setText(new ICSetting("xPlusRotate", "绕X轴正旋转", "X-plus rotate",
				xClock, 2));
		xClock.setBounds(20, 350, 102, 23);

		IButton rxClock = new IButton();
		kzPanel.add(rxClock);
		rxClock.addActionListener(e -> {
			eOT();
			if (fractal.getSff() != 1)
			{
				fractal.setSff(1);
				drawFractal();
			}
		});
		rxClock.setText(new ICSetting("reset", "恢  复", "Reset", rxClock, 1));
		rxClock.setBounds(20, 375, 102, 23);

		IButton xUnClock = new IButton();
		kzPanel.add(xUnClock);
		xUnClock.addActionListener(new XunclockButtonActionListener());
		xUnClock.setText(new ICSetting("xMinusRotate", "绕X轴反旋转",
				"X-minus rotate", xClock, 2));
		xUnClock.setBounds(20, 400, 102, 23);

		grow = new IButton();
		kzPanel.add(grow);
		grow.addActionListener(new GrowButtonActionListener());
		grow.setText(new ICSetting("fraGrow", "分形生长", "Fractal Grow"), true);
		grow.setBounds(20, 440, 102, 23);
		dis = new IButton();
		kzPanel.add(dis);
		dis.addActionListener(new DisButtonActionListener());
		dis.setText(new ICSetting("fraShrink", "分形消除", "Fractal Shrink"), true);
		dis.setBounds(20, 465, 102, 23);

		IButton stB = new IButton();
		kzPanel.add(stB);
		stB.setBackground(new Color(255, 80, 130));
		stB.setDefaultAlpha(0.65f);
		stB.setHoverAlpha(0.9f);
		stB.addActionListener(new StopButtonActionListener());
		stB.setFont(FontTools.getLargeFont());
		stB.setText(new ICSetting("stop", "停 止", "Stop"));
		stB.setBounds(20, 505, 102, 25);
	}

	private DHSetDialog dhSetDialog;

	private final Color setColor = new Color(127, 255, 0);
	private final Color makeColor = new Color(255, 0, 255);

	private void initDHDialog()
	{
		dhDialog = new RDialog(this);
		dhDialog.addClosingOperator(o -> {
			checkBox3.setSelected(false);
			s3 = false;
		});

		ActScaleImageComp setComp = new ActScaleImageComp(
				(LazyScaleIcon) UIData.getDefaultUIData().frameUI.setIcon);
		setComp.addClickOperator((Object o) ->
		{
			if (dhSetDialog == null)
				dhSetDialog = new DHSetDialog(dhDialog);
			dhSetDialog.setLocationRelativeTo(FractalFrame.this);
			dhSetDialog.setVisible(true);
		});
		dhDialog.addActionComponent(setComp);

		dhDialog.setSize(935, 110);
		dhDialog.setResizable(false);
		Container dhPanel = dhDialog.getContentPane();
		dhPanel.setLayout(null);

		tabbedPane = new ITabbedPane();
		dhDialog.addToLayeredPane(tabbedPane);
		tabbedPane.setBounds(8, 2, 675, 110);
		DragCompUtils.setMovable(tabbedPane, dhDialog);

		createCustomPanel();
		createSFPanel();
		// tabbedPane.addTab("测试", new JPanel());
		createGrowPanel();
		createGifPanel();

		ILabel zLabel = new ILabel();
		dhPanel.add(zLabel);
		zLabel.setText(new ICSetting("fps", " 视频帧率", "Vidoe FPS", zLabel, 1));
		zLabel.setBounds(726, 8, 65, 18);

		String[] fpStrings = new String[frameRates.length];
		for (int i = 0; i < fpStrings.length; i++)
			fpStrings[i] = frameRates[i] + "fps";

		fpsBox = new JComboBox(fpStrings);
		dhPanel.add(fpsBox);
		fpsBox.addActionListener(new fpsBoxActionListener());
		fpsBox.setBounds(790, 6, 90, 22);
		fpsBox.setSelectedIndex(7);
		IButton openAB = new IButton();
		dhPanel.add(openAB);
		openAB.setBounds(705, 45, 100, 28);
		openAB.addActionListener(new OpenAniButtonActionListener());

		openAB.setText(new ICSetting("openAni", "打开动画文件", "Open animation",
				openAB, 1));
		saveAB = new IButton();
		dhPanel.add(saveAB);
		saveAB.setBounds(810, 45, 100, 28);
		saveAB.addActionListener(new SaveAniButtonActionListener());
		saveAB.setText(new ICSetting("saveAni", "保存动画文件", "Save animation",
				saveAB, 1));
		tabbedPane.addChangeListener(e -> {
			animateID = tabbedPane.getSelectedIndex();
			saveAB.setEnabled(bools[animateID]);
		});
		tabbedPane.setSelectedIndex(animateID);
	}

	private void initSZDialog()
	{
		szDialog = new RDialog(this);
		szDialog.addClosingOperator(o -> {
			checkBox4.setSelected(false);
			s4 = false;
		});
		szDialog.setSize(140, 485);
		szDialog.setResizable(false);
		Container foP = szDialog.getContentPane();
		foP.setLayout(null);
		coreGroup = new ButtonGroupPanel();
		foP.add(coreGroup);
		coreGroup.setLayout(null);
		coreGroup.setBounds(22, 55, 95, 105);
		IRadioButton[] coreRadios = new IRadioButton[5];
		for (int i = 0; i < coreRadios.length; i++)
		{
			coreRadios[i] = new IRadioButton();
			coreGroup.add(coreRadios[i]);
			coreRadios[i].setBounds(5, 5 + i * 20, 90, 18);
		}

		coreRadios[0].setText(
				new ICSetting("singleCore", "使用单核", "Single-core"), true);
		coreRadios[1].setText(new ICSetting("dualCore", "使用双核", "Dual-core"),
				true);
		coreRadios[2].setText(new ICSetting("quadCore", "使用四核", "Quad-core"),
				true);
		coreRadios[3].setText(new ICSetting("sixCore", "使用六核", "Six-core"));
		coreRadios[4].setText(new ICSetting("eightCore", "使用八核", "Eight-core"));
		coreGroup.setSelectedIndex(core / 2);
		//		if (core == 2)
		//			coreRadios[1].setSelected(true);
		//		else if (core == 4)
		//			coreRadios[2].setSelected(true);
		//		else
		//			coreRadios[0].setSelected(true);
		coreGroup.addActionListener(new CoreGroupActionListener());

		abB = new TransButton();
		foP.add(abB);
		abB.addClickOperator(new AboutButtonOperator());
		abB.setText(new ICSetting("aboutAuthor", "关于作者", "About author"), true);
		abB.setBounds(20, 235, 97, 35);
		IRichTextLabel helpLabel = new IRichTextLabel();
		foP.add(helpLabel);
		helpLabel.addMouseListener(new HelpLabelMouseListener());
		helpLabel.setParameter(
				new ICSetting("showHelpInfo", "显示帮助信息", "  Help Info"),
				FontTools.getLargeFont(), Color.cyan);
		helpLabel.setLocation(25, 175);
		helpLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
		infoCheckBox = new ICheckBox();
		foP.add(infoCheckBox);
		infoCheckBox.addActionListener(new InfoCheckBoxActionListener());
		infoCheckBox.setOpaque(false);

		infoCheckBox.setText(new ICSetting("showWhenExpand", "展开时显示",
				"Show when expanded", infoCheckBox, 5));
		infoCheckBox.setBounds(20, 200, 110, 18);
		infoCheckBox.setSelected(showInfo);

		hB = new IButton();
		hB.setBounds(10, 5, 115, 40);
		foP.add(hB);
		hB.addActionListener(new HelpButtonActionListener());
		hB.setFont(FontTools.getLargeFont());
		hB.setBackground(Color.WHITE);
		hB.setDefaultAlpha(0.2f);
		hB.setHoverAlpha(0.5f);
		hB.setText(new ICSetting("aboutSoft", "软件说明", "About Soft"), true);

		IButton oFB = new IButton();
		foP.add(oFB);
		oFB.setBounds(15, 285, 107, 28);
		oFB.addActionListener(new OpenFraButtonActionListener());
		oFB.setBackground(new Color(153, 255, 204));
		oFB.setText(new ICSetting("openFra", "打开分形参数", "Open fractal"));
		IButton sFB = new IButton();
		foP.add(sFB);
		sFB.setBounds(15, 320, 107, 28);
		sFB.addActionListener(new SaveFraButtonActionListener());
		sFB.setBackground(new Color(153, 255, 255));
		sFB.setText(new ICSetting("saveFra", "保存分形参数", "Save fractal"));
		ArrayList<IString> list = IString.createArray("parameter", "    参数",
				"  parameter", 1, 70);
		list.add(0, new IString("fromNet", "    从网上获取", "   get from net"));
		list.add(0, new IString("presetParameter", "预置分形参数", "Pre parameter"));
		fraC = new IComboBox(list.toArray());
		foP.add(fraC);
		fraC.setBounds(10, 365, 118, 30);
		fraC.addActionListener(new FraCActionListener());

		IButton iniB = new IButton();
		foP.add(iniB);
		iniB.setBounds(10, 410, 118, 28);
		iniB.addActionListener(new IniBActionListener());
		iniB.setBackground(new Color(102, 255, 102));
		iniB.setText(new ICSetting("setAsInitial", "设为初始界面",
				"Set as init interface"), true);
	}

	private void createCustomPanel()
	{
		JPanel panel = tabbedPane.createTabbedPanel(
				new IString("customAnimation", "自定义动画", "Custom animation"));
		panel.setLayout(null);
		ILabel aBL = new ILabel();
		panel.add(aBL);
		aBL.setText(new ICSetting("transition", "过渡帧数", "Transition", aBL, 1));
		aBL.setBounds(18, 17, 58, 18);
		final SpinnerNumberModel nbkSNM = new SpinnerNumberModel(aniN, 1, 5000,
				1);
		JSpinner aBS = new JSpinner(nbkSNM);
		panel.add(aBS);
		aBS.addChangeListener(e -> aniN = nbkSNM.getNumber().intValue());
		aBS.setBounds(78, 14, 66, 24);

		IButton aFB = new IButton();
		panel.add(aFB);
		aFB.setBackground(setColor);
		aFB.addActionListener(new AddFrameActionListener());

		aFB.setText(new ICSetting("addToKey", "将当前加入关键帧", "Add to keyframe"),
				true);
		aFB.setBounds(15, 46, 128, 23);

		deB = new IButton();
		panel.add(deB);
		deB.addActionListener(new DeBActionListener());
		deB.setBackground(Color.orange);

		deB.setText(new ICSetting("deleteLastKey", "删除最后关键帧",
				"Delete last keyframe"), true);
		deB.setBounds(150, 15, 130, 23);

		rB = new IButton();
		panel.add(rB);
		rB.setBackground(Color.orange);
		rB.addActionListener(new ResetActionListener());

		rB.setText(
				new ICSetting("resetAllKey", "重置所有关键帧", "Reset all keyframe"),
				true);
		rB.setBounds(150, 46, 130, 23);

		sAB = new IButton();
		panel.add(sAB);
		sAB.addActionListener(new StartAnimateActionListener());
		sAB.setText(new ICSetting("keyframeAni", "观看关键帧动画", "Keyframe animate"),
				true);
		sAB.setBounds(290, 15, 136, 23);
		aMB = new IButton();
		panel.add(aMB);
		aMB.setBackground(makeColor);
		aMB.addActionListener(new KfVidoeActionListener());
		aMB.setText(new ICSetting("keyframeVideo", "生成关键帧视频", "Keyframe video"),
				true);
		aMB.setBounds(290, 46, 136, 23);

		ILabel stL = new IRichLabel();
		panel.add(stL);
		stL.setForeground(Color.YELLOW);

		stL.setText(new ICSetting("totalKey", "共可定义30关键帧 ,",
				"30 keys can be defined,", stL, 3));
		stL.setBounds(440, 20, 110, 18);
		ILabel stL2 = new IRichLabel();
		panel.add(stL2);
		stL2.setForeground(Color.red);

		stL2.setText(new ICSetting("least2key", "至少定义2关键帧",
				"define at least 2 keys", stL2, 3));
		stL2.setBounds(552, 20, 110, 18);

		asL = new IRichLabel();
		panel.add(asL);
		asL.setForeground(Color.CYAN);
		asL.setBounds(440, 42, 220, 18);
		asL.setText(new ICSetting("frameInfo", "已定义 %d  关键帧 , 动画一共有 %d 帧",
				"%d keys is defined, has a total of %d frames", asL, 3));
		asL.setReplaceData(0, 0);
	}

	private void disableCustom()
	{
		kFC = 0;
		fC = 0;
		customDatas.clear();
		asL.setReplaceData(0, 0);
		sAB.setEnabled(false);
		aMB.setEnabled(false);
		deB.setEnabled(false);
		rB.setEnabled(false);
		bools[0] = false;
	}

	private void enableCustom()
	{
		kFC = customDatas.size();
		if (kFC < 2)
			return;
		fC = 0;
		for (int i = 1; i <= kFC; i++)
			fC = fC + aniNBK[i];
		asL.setReplaceData(kFC, fC);
		sAB.setEnabled(true);
		aMB.setEnabled(true);
		deB.setEnabled(true);
		rB.setEnabled(true);
		saveAB.setEnabled(true);
		bools[0] = true;
	}

	private void createSFPanel()
	{
		JPanel panel = tabbedPane.createTabbedPanel(
				new IString("zoomAnimation", "缩放动画 ", "Zoom animation"));
		panel.setLayout(null);
		ILabel sfL = new ILabel();
		panel.add(sfL);
		sfL.setText(new ICSetting("SFmin", "缩放最小参数", "Min parameter", sfL, 2));
		sfL.setBounds(10, 17, 82, 18);
		sfT = new JTextField();
		sfT.setFont(FontTools.getCustomFont(11));
		panel.add(sfT);
		sfT.setBounds(90, 15, 170, 23);
		ILabel sfM = new ILabel();
		panel.add(sfM);
		sfM.setText(new ICSetting("SFmax", "缩放最大参数", "Max parameter", sfM, 2));
		sfM.setBounds(10, 48, 82, 18);
		sfT2 = new JTextField();
		sfT2.setFont(FontTools.getCustomFont(11));
		panel.add(sfT2);
		sfT2.setBounds(90, 46, 170, 23);
		sfB = new IButton();
		panel.add(sfB);
		sfB.setBackground(setColor);
		sfB.addActionListener(new SfMinButtonActionListener());
		sfB.setText(new ICSetting("setSFmin", "将当前设为最小参数",
				"Set current as min parameter", sfB, 2));
		sfB.setBounds(265, 15, 165, 23);

		sfmB = new IButton();
		sfmB.setBounds(265, 46, 165, 23);
		sfmB.setBackground(setColor);
		panel.add(sfmB);
		sfmB.addActionListener(new SfMaxButtonActionListener());
		sfmB.setText(new ICSetting("setSFmax", "将当前设为最大参数",
				"Set current as max parameter", sfmB, 2));
		zOB = new IButton();
		panel.add(zOB);
		zOB.addActionListener(new ZoomOutButtonActionListener());

		zOB.setText(new ICSetting("zoomOutAni", "观看缩小动画", "Zoom-out animation",
				zOB, 2));
		zOB.setBounds(435, 15, 120, 23);
		zIB = new IButton();
		panel.add(zIB);
		zIB.addActionListener(new ZoomInButtonActionListener());
		zIB.setText(new ICSetting("zoomInAni", "观看放大动画", "Zoom-in animation",
				zIB, 2));
		zIB.setBounds(435, 46, 120, 23);

		zOAB = new IButton();
		panel.add(zOAB);
		zOAB.setBackground(makeColor);
		zOAB.addActionListener(new ZOutVidoeActionListener());

		zOAB.setText(new ICSetting("zoomOutVideo", "生成缩小视频", "Zoom-out video",
				zOAB, 2));
		zOAB.setBounds(560, 15, 100, 23);
		zIAB = new IButton();
		panel.add(zIAB);
		zIAB.setBackground(makeColor);
		zIAB.addActionListener(new ZInVidoeActionListener());
		zIAB.setText(new ICSetting("zoomInVideo", "生成放大视频", "Zoom-in video",
				zIAB, 2));
		zIAB.setBounds(560, 46, 100, 23);
	}

	private void disableSF()
	{
		zoomDatas[0] = zoomDatas[1] = null;
		sfT.setText(null);
		sfT2.setText(null);
		zOB.setEnabled(false);
		zIB.setEnabled(false);
		zOAB.setEnabled(false);
		zIAB.setEnabled(false);
		bools[1] = false;
	}

	private void enableSF()
	{
		if (zoomDatas[0] != null)
			sfT2.setText(String.valueOf(zoomDatas[0].getDxy()));
		if (zoomDatas[1] != null)
			sfT.setText(String.valueOf(zoomDatas[1].getDxy()));
		sfFrame = getSfFrame();
		if (sfFrame == 0)
			return;
		zOB.setEnabled(true);
		zIB.setEnabled(true);
		zOAB.setEnabled(true);
		zIAB.setEnabled(true);
		saveAB.setEnabled(true);
		bools[1] = true;
	}

	int startG, endG;
	IButton growAButton, growVButton, startButton, endButton;
	JTextField startText, endText;

	private void createGrowPanel()
	{
		JPanel panel = tabbedPane.createTabbedPanel(
				new IString("growAnimation", "生长动画 ", "Grow animation"));
		panel.setLayout(null);
		ILabel startLabel = new ILabel();
		panel.add(startLabel);
		startLabel.setHorizontalAlignment(JLabel.CENTER);
		startLabel.setText(new ICSetting("growStart", "  开始参数",
				"Start parameter", startLabel, 1));
		startLabel.setBounds(20, 17, 92, 18);
		startText = new JTextField();
		panel.add(startText);
		startText.setBounds(115, 15, 90, 23);
		startText.requestFocus();
		ILabel endLabel = new ILabel();
		panel.add(endLabel);
		endLabel.setHorizontalAlignment(JLabel.CENTER);
		endLabel.setText(new ICSetting("growEnd", "  结束参数", "End parameter ",
				endLabel, 1));
		endLabel.setBounds(20, 48, 92, 18);
		endText = new JTextField();
		panel.add(endText);
		endText.setBounds(115, 46, 90, 23);

		startButton = new IButton();
		panel.add(startButton);
		startButton.setBackground(setColor);
		startButton.addActionListener(new StartRActionListener());

		startButton.setText(new ICSetting("setGrowStart", "将当前设为开始参数",
				"Set current as start parameter", startButton, 2));
		startButton.setBounds(225, 15, 170, 23);

		endButton = new IButton();
		endButton.setBounds(225, 46, 170, 23);
		endButton.setBackground(setColor);
		panel.add(endButton);
		endButton.addActionListener(new EndRActionListener());
		endButton.setText(new ICSetting("setGrowEnd", "将当前设为结束参数",
				"Set current as end parameter", endButton, 2));

		growAButton = new IButton();
		panel.add(growAButton);
		growAButton.addActionListener(new GrowAnimateActionListener());
		growAButton.setText(new ICSetting("growAni", "观看生长动画", "Grow animation",
				growAButton, 1));
		growAButton.setBounds(410, 15, 120, 23);
		growVButton = new IButton();
		panel.add(growVButton);
		growVButton.setBackground(makeColor);
		growVButton.addActionListener(new GrowVidoeActionListener());
		growVButton.setText(new ICSetting("saveGrowVideo", "生成生长视频",
				"Save grow video", growAButton, 1));
		growVButton.setBounds(410, 46, 120, 23);
	}

	private void disableGrow()
	{
		startG = endG = -1;
		growAButton.setEnabled(false);
		growVButton.setEnabled(false);
		startText.setText(null);
		endText.setText(null);
		bools[2] = false;
	}

	private void enableGrow()
	{
		if (startG >= 0)
			startText.setText(String.valueOf(startG));
		if (endG >= 0)
			endText.setText(String.valueOf(endG));
		if (startG >= 0 && endG >= 0 && startG != endG)
		{
			growAButton.setEnabled(true);
			growVButton.setEnabled(true);
			saveAB.setEnabled(true);
			bools[2] = true;
		}
	}

	private void createGifPanel()
	{
		JPanel panel = tabbedPane.createTabbedPanel(
				new IString("gifMaker", "生成GIF ", "Make GIF"));
		panel.setLayout(null);
		//		ILabel aBL = new ILabel();
		//		panel.add(aBL);
		//		aBL.setText(
		//				new ICSetting("transition", "过渡帧数", "Transition", aBL, true));
		//		aBL.setBounds(18, 33, 58, 18);
		//		final SpinnerNumberModel nbkSNM = new SpinnerNumberModel(gifN, 0, 10,
		//				1);
		//		JSpinner aBS = new JSpinner(nbkSNM);
		//		panel.add(aBS);
		//		aBS.addChangeListener(new ChangeListener()
		//		{
		//			@Override
		//			public void stateChanged(ChangeEvent e)
		//			{
		//				gifN = nbkSNM.getNumber().intValue();
		//			}
		//		});
		//		aBS.setBounds(78, 30, 50, 24);

		IButton aFB = new IButton();
		panel.add(aFB);
		aFB.setBackground(setColor);
		aFB.addActionListener(e -> {
			gifDatas.add(fractal.getNewRecordData());
			gifF++;
			if (gifF == 1)
			{
				preGifB.setEnabled(true);
				saveGifB.setEnabled(true);
			}
			gifFL.setReplaceData(gifF);
		});
		aFB.setText(new ICSetting("addToGif", "将当前帧加入GIF",
				"Add current frame to GIF", aFB, 2));
		aFB.setBounds(150, 15, 140, 23);

		IButton rB = new IButton();
		panel.add(rB);
		rB.setBackground(Color.orange);
		rB.addActionListener(e -> disableGif());
		rB.setText(new ICSetting("resetGif", "重置GIF", "Reset GIF"), true);
		rB.setBounds(150, 46, 140, 23);

		preGifB = new IButton();
		panel.add(preGifB);
		preGifB.addActionListener(new gifPreviewActionListener());
		preGifB.setText(new ICSetting("previewGif", "预览GIF", "GIF preview"),
				true);
		preGifB.setBounds(320, 15, 120, 23);

		saveGifB = new IButton();
		panel.add(saveGifB);
		saveGifB.setBackground(makeColor);
		saveGifB.addActionListener(new SaveGifActionListener());
		saveGifB.setText(new ICSetting("saveGif", "生成GIF", "Save GIF"), true);
		saveGifB.setBounds(320, 46, 120, 23);

		gifFL = new IRichLabel();
		panel.add(gifFL);
		gifFL.setForeground(Color.yellow);
		gifFL.setHorizontalAlignment(SwingConstants.CENTER);
		gifFL.setBounds(460, 32, 180, 18);
		gifFL.setText(new ICSetting("frameInfo", "GIF图像共有 %d 帧",
				"GIF image has a total of %d frames", gifFL, 2));
		gifFL.setReplaceData(0);
	}

	private void disableGif()
	{
		gifF = 0;
		gifDatas.clear();
		gifFL.setReplaceData(0);
		preGifB.setEnabled(false);
		saveGifB.setEnabled(false);
	}

	private void createGradientColorDialog()
	{
		gradientColorDialog = new GradientColorDialog(this);
	}

	public void setToBeGradientType()
	{
		colorType = 1;
		colorTypeBox.setSelectedIndex(colorType);
		graColorLabel.repaint();
	}

	public void resetDHDialog()
	{
		disableCustom();
		disableSF();
		disableGrow();
		disableGif();
		saveAB.setEnabled(false);
	}

	public void setColorMatchSpace(int type, boolean b)
	{
		colorType = type;
		switch (type)
		{
			case 0:
				colorMatchSpace = FractalColor.getNormalColorSpace();
				break;
			case 1:
				colorMatchSpace = FractalColor
						.getGradualColorSpace(gradualColors);
				break;
			case 2:
				colorMatchSpace = FractalColor.getFullColorSpace();
		}
		for (Fractal fractal : fractalArr)
			fractal.setColorSpace(colorMatchSpace);
		if (b)
			drawNewColorFractal();
	}

	public void setColorType(int type, boolean b)
	{
		reColor = b;
		colorTypeBox.setSelectedIndex(type);
		reColor = true;
	}

	public void setFilter(int filterID)
	{
		filter = FractalFilter.filterArr[filterID];
		for (Fractal fractal : fractalArr)
			fractal.setFilter(filter);
	}

	private BufferedImage createLogoImage(Fractal fr, int core)
	{
		BufferedImage image = fr.getFractalImage(null, core);
		Graphics gra = image.getGraphics();
		gra.drawImage(logo, fr.getWidth() - logoWidth - 15, fr.getHeight() - logoHeight - 15,
				logoWidth, logoHeight, null);
		gra.dispose();
		return image;
	}

	//	private BufferedImage createNewLogoImage(Fractal fractal)
	//	{
	//		int W = fractal.W, H = fractal.H;
	//		BufferedImage image = fractal.getFractalImage(null);
	//		BufferedImage bImage = new BufferedImage(W, H,
	//				BufferedImage.TYPE_INT_RGB);
	//		Graphics gra = bImage.getGraphics();
	//		gra.drawImage(image, 0, 0, null);
	//		gra.drawImage(logo, W - logoWidth - 15, H - logoHeight - 15, logoWidth,
	//				logoHeight, null);
	//		gra.dispose();
	//		return image;
	//	}

	public void repaintFractal()
	{
		fraImage = fractal.getFractalImage(fraImage, core);
		drawPanel.repaint();
	}

	public void drawFractal()
	{
		// long t = System.currentTimeMillis();
		fractal.calculateFractalInThread(core);
		repaintFractal();
		// System.out.println(System.currentTimeMillis() - t);
	}

	public void drawNewColorFractal()
	{
		fractal.calculateNewColorFractal();
		repaintFractal();
	}

	public void drawNewNFractal(int newN)
	{
		fractal.calculateNewNFractal(newN);
		repaintFractal();
	}

	public void rotateFractal(double ang)
	{
		fractal.rotateFractal(ang);
		drawFractal();
	}

	public void xRotate(int f)
	{
		fractal.xRotate(f);
		drawFractal();
	}

	//	public void recordFractal()
	//	{
	//		if (rC == records.size())
	//			records.add(fractal.getRecordData());
	//		else if (rC < records.size())
	//		{
	//			fractal.center();
	//			records.get(rC).setFractalData(fractal);
	//		}
	//	}

	//	public void getRecordFractal()
	//	{
	//		fractal.setFractalData(records.get(rC));
	//	}

	public void saveColorPNG(File file, Fractal fr)
	{
		fr.createFractalPixels();
		BufferedImage image = createLogoImage(fr, core);
		try
		{
			ImageIO.write(image, "png", file);
		} catch (Exception ignored)
		{
		}
		image.flush();
	}

	String folderPath;
	File outFolder;

	int[] ap, an;
	int totalFrames;

	public BufferedImage createAniImage(int frame, final Fractal fr, int core)
	{
		fr.setFractalData(allDatas.get(frame));
		fr.calculateFractalInThread(core);
		return createLogoImage(fr, core);
	}

	public BufferedImage createGrowAniImage(int frame, final Fractal fr,
			int core)
	{
		if (startG < endG)
			fr.grow();
		else
			fr.melt();
		fr.calculateFractalInThread(core);
		return createLogoImage(fr, core);
	}

	Jim2Mov currentJim2Mov;

	public void saveFractalVideo(String videoPath, float fps, final Fractal fr,
			final int core)
	{
		int l = fr.getWidth() * fr.getHeight();
		if (ap == null || ap.length != l)
		{
			ap = new int[l];
			an = new int[l];
		}
		fr.setFractalPNData(ap, an);
		int[] colorMSpace = new int[colorMatchSpace.length];
		System.arraycopy(colorMatchSpace, 0, colorMSpace, 0,
				colorMatchSpace.length);
		fr.setColorSpace(colorMSpace);
		DefaultMovieInfoProvider dmip = new DefaultMovieInfoProvider(
				VideoTools.createMediaLocator(videoPath));
		dmip.setMWidth(fr.getWidth());
		dmip.setMHeight(fr.getHeight());
		totalFrames = allDatas.size();
		dmip.setNumberOfFrames(totalFrames);
		dmip.setFPS(fps);
		try
		{
			currentJim2Mov = new Jim2Mov(frame -> {
				try
				{
					return MovieUtils.bufferedImageToJPEG(
							createAniImage(frame, fr, core), 1.0f);
				} catch (IOException e)
				{
					e.printStackTrace();
				}
				return null;
			}, dmip, saveProgressListener);
			currentJim2Mov.saveMovie(MovieInfoProvider.TYPE_QUICKTIME_JPEG);
		} catch (MovieSaveException e)
		{
			e.printStackTrace();
		}
	}

	public void saveGrowVideo(String videoPath, float fps, final Fractal fr,
			final int core)
	{
		int l = fr.getWidth() * fr.getHeight();
		if (ap == null || ap.length != l)
		{
			ap = new int[l];
			an = new int[l];
		}
		fr.setFractalPNData(ap, an);
		int[] colorMSpace = new int[colorMatchSpace.length];
		System.arraycopy(colorMatchSpace, 0, colorMSpace, 0,
				colorMatchSpace.length);
		fr.setColorSpace(colorMSpace);
		DefaultMovieInfoProvider dmip = new DefaultMovieInfoProvider(
				VideoTools.createMediaLocator(videoPath));
		dmip.setMWidth(fr.getWidth());
		dmip.setMHeight(fr.getHeight());
		totalFrames = Math.abs(endG - startG);
		dmip.setNumberOfFrames(totalFrames);
		dmip.setFPS(fps);
		fr.setMaxN(startG);
		fr.calculateFractalInThread(core);
		try
		{
			currentJim2Mov = new Jim2Mov(frame -> {
				try
				{
					return MovieUtils.bufferedImageToJPEG(
							createGrowAniImage(frame, fr, core), 1.0f);
				} catch (IOException e)
				{
					e.printStackTrace();
				}
				return null;
			}, dmip, saveProgressListener);
			currentJim2Mov.saveMovie(MovieInfoProvider.TYPE_QUICKTIME_JPEG);
		} catch (MovieSaveException e)
		{
			e.printStackTrace();
		}
	}

	SaveProgressListener saveProgressListener = new SaveProgressListener();

	class SaveProgressListener implements FrameSavedListener
	{
		@Override
		public void frameSaved(int frameNumber)
		{
			progressWindow
					.setValue((int) ((double) frameNumber / totalFrames * 100));
			// System.out.println(frameNumber / totalFrames);
		}
	}

	int[] sp, sn;

	public void saveColorPicture(File file, final Fractal fr, int core)
	{
		int l = fr.getWidth() * fr.getHeight();
		if (sp == null || sp.length != l)
		{
			sp = new int[l];
			sn = new int[l];
		}
		fr.setFractalPNData(sp, sn);
		fr.calculateFractalInThread(core);
		BufferedImage bImage = createLogoImage(fr, core);
		String ext = TextTools.getFileExt(file.getName());
		try
		{
			ImageIO.write(bImage, ext, file);
		} catch (Exception ignored)
		{
		}
		bImage.flush();
	}

	public void moveDown(int l)
	{
		fractal.moveDown(l);
		repaintFractal();
	}

	public void moveUp(int l)
	{
		fractal.moveUp(l);
		repaintFractal();
	}

	public void moveLeft(int l)
	{
		fractal.moveLeft(l);
		repaintFractal();
	}

	public void moveRight(int l)
	{
		fractal.moveRight(l);
		repaintFractal();
	}

	public void moveForward()
	{
		if (fractal.moveForward())
		{
			drawFractal();
			updateRecord();
		}
	}

	public void moveBackward()
	{
		if (fractal.moveBackward())
		{
			drawFractal();
			updateRecord();
		}
	}

	public void largerStep()
	{
		fractal.largerStep(zoomFactor);
		drawFractal();
	}

	public void smallerStep()
	{
		fractal.smallerStep(zoomFactor);
		drawFractal();
	}

	public void changeColorAct(int mx, int my)
	{
		if (palette.currentColor != null)
		{
			int rgb = palette.currentColor.getRGB();
			int n = recordN[MW * my + mx];
			if (n == fractal.getMaxN())
				fractal.setBackColorPix(rgb);
			else
				colorMap.add(n, rgb);
			repaintFractal();
		}
	}

	public void clearColorAct(int mx, int my)
	{
		int n = recordN[MW * my + mx];
		if (n == fractal.getMaxN())
		{
			fractal.setBackColorPix(originalBackPix);
			repaintFractal();
		} else if (colorMap.remove(n))
			repaintFractal();
	}

	public void clearAllColor()
	{
		if (fractalID == 5)
			return;
		colorMap.clear();
		fractal.setBackColorPix(originalBackPix);
		repaintFractal();
	}

	// 确保只有一个线程运行
	public void eOT()
	{
		if (tG)
		{
			tG = false;
			try
			{
				Thread.sleep(500);
			} catch (InterruptedException ie)
			{
				ie.printStackTrace();
			}
		}
	}

	IString setOKString = new IString("setOK", "设置成功", "Set successed");

	public void setCustomFractal()
	{
		fractal.putCustomData();
		SettingTools.putDefaultSettingData("saveW", saveW);
		SettingTools.putDefaultSettingData("saveH", saveH);
		SettingTools.putDefaultSettingData("colorType", colorType);
		if (colorType == 1)
			for (int i = 0; i < gradualColors.length; i++)
				SettingTools.putDefaultSettingData("gradualColors" + i,
						gradualColors[i].getRGB());
		colorMap.putCustomData();
		SettingTools.putDefaultSettingData("bPix", fractal.getBackColorPix());
		SettingTools.putDefaultSettingData("filterID", filterID);
		HintWindow.showHint(setOKString, this);
	}

	public void saveFraFile(File f)
	{
		if (f == null)
			return;
		DataOutputStream dos = null;
		try
		{
			dos = new DataOutputStream(new FileOutputStream(f));
			dos.writeInt(VERSION);
			dos.writeInt(fractalID);
			dos.writeInt(filterID);
			fractal.writeToDataStream(dos);
			dos.writeInt(colorType);
			if (colorType == 1)
				for (Color gradualColor : gradualColors)
					dos.writeInt(gradualColor.getRGB());
			colorMap.writeToDataStream(dos);
			dos.writeInt(fractal.getBackColorPix());
			dos.writeInt(saveW);
			dos.writeInt(saveH);
			dos.close();
		} catch (Exception e1)
		{
			e1.printStackTrace();
			try
			{
				if (dos != null)
					dos.close();
			} catch (Exception ignored)
			{
			}
			HintWindow.showHint(ITexts.fileErrString, this);
		}
		HintWindow.showHint(ITexts.saveOkString, this);
	}

	public void openFraFile(File f)
	{
		if (f == null)
			return;
		DataInputStream dis = null;
		int backColorPix;
		try
		{
			dis = new DataInputStream(new FileInputStream(f));
			int version = dis.readInt();
			if (version < VERSION)
				fractalID = version;
			else
				fractalID = dis.readInt();
			filterID = dis.readInt();
			fractal = fractalArr[fractalID];
			fractal.readFromDataStream(dis, version);
			colorType = dis.readInt();
			if (colorType == 1)
				for (int i = 0; i < gradualColors.length; i++)
					gradualColors[i] = new Color(dis.readInt());
			colorMap.readFromDataStream(dis);
			backColorPix = dis.readInt();
			saveW = dis.readInt();
			saveH = dis.readInt();
			dis.close();
		} catch (Exception e1)
		{
			ROptionPane.showMessageDialog(this, openFraError,
					ITexts.fileErrString);
			try
			{
				if (dis != null)
					dis.close();
			} catch (Exception ignored)
			{
			}
			return;
		}
		setFilter(filterID);
		setColorType(colorType, false);
		fractal.setColorMap(colorMap);
		fractal.setBackColorPix(backColorPix);

		fractal.initRecordData();
		openLargePanel();
		updateRecord();
		fractalGroup.setSelectedIndex(fractalID);
		filterGroup.setSelectedIndex(filterID);
		wT.setText(String.valueOf(saveW));
		hT.setText(String.valueOf(saveH));
		sizeBox.setSelectedIndex(0);
		resetDHDialog();

		if (colorType == 1)
			graColorLabel.repaint();
		if (fractalID == 5)
			chooseNewton();
		else
			unChooseNewton();
	}

	public void saveAnimateFile(File f)
	{
		if (f == null)
			return;
		DataOutputStream dos = null;
		try
		{
			dos = new DataOutputStream(new FileOutputStream(f));
			dos.writeInt(VERSION);
			dos.writeInt(fractalID);
			dos.writeInt(filterID);
			fractal.writeToDataStream(dos);
			dos.writeInt(colorType);
			if (colorType == 1)
				for (Color gradualColor : gradualColors)
					dos.writeInt(gradualColor.getRGB());
			colorMap.writeToDataStream(dos);
			dos.writeInt(fractal.getBackColorPix());
			dos.writeInt(saveW);
			dos.writeInt(saveH);
			dos.writeInt(fpsBox.getSelectedIndex());
			dos.writeInt(animateID);
			switch (animateID)
			{
				case 0:
					dos.writeInt(kFC);
					for (int i = 1; i <= kFC; i++)
						dos.writeInt(aniNBK[i]);
					for (FractalData fd : customDatas)
						fd.writeToDataStream(dos);
					break;
				case 1:
					zoomDatas[0].writeToDataStream(dos);
					zoomDatas[1].writeToDataStream(dos);
					dos.writeDouble(zoomFactor);
					break;
				case 2:
					dos.writeInt(startG);
					dos.writeInt(endG);
			}
			dos.close();
		} catch (Exception e1)
		{
			e1.printStackTrace();
			try
			{
				if (dos != null)
					dos.close();
			} catch (Exception ignored)
			{
			}
			HintWindow.showHint(ITexts.fileErrString, this);
		}
		HintWindow.showHint(ITexts.saveOkString, this);
	}

	IString openAniError = new IString("openAniError", "打开ani文件出错！",
			"ani file error!");
	IString openFraError = new IString("openFraError", "打开fra文件出错！",
			"fra file error!");

	public void openAnimateFile(File f)
	{
		if (f == null)
			return;
		DataInputStream dis = null;
		int version, fpsIndex, backColorPix;
		try
		{
			dis = new DataInputStream(new FileInputStream(f));
			version = dis.readInt();
			if (version < VERSION)
				fractalID = version;
			else
				fractalID = dis.readInt();
			filterID = dis.readInt();
			fractal = fractalArr[fractalID];
			fractal.readFromDataStream(dis, version);
			colorType = dis.readInt();
			if (colorType == 1)
				for (int i = 0; i < gradualColors.length; i++)
					gradualColors[i] = new Color(dis.readInt());
			colorMap.readFromDataStream(dis);
			backColorPix = dis.readInt();
			saveW = dis.readInt();
			saveH = dis.readInt();
			fpsIndex = dis.readInt();
			animateID = dis.readInt();
			switch (animateID)
			{
				case 0:
					kFC = dis.readInt();
					for (int i = 1; i <= kFC; i++)
						aniNBK[i] = dis.readInt();
					customDatas.clear();
					for (int i = 0; i < kFC; i++)
					{
						FractalData fd = new FractalData();
						fd.readFromDataStream(dis, version);
						customDatas.add(fd);
					}
					break;
				case 1:
					if (zoomDatas[0] == null)
						zoomDatas[0] = new FractalData();
					if (zoomDatas[1] == null)
						zoomDatas[1] = new FractalData();
					zoomDatas[0].readFromDataStream(dis, version);
					zoomDatas[1].readFromDataStream(dis, version);
					zoomFactor = dis.readDouble();
					break;
				case 2:
					startG = dis.readInt();
					endG = dis.readInt();
			}
			dis.close();
		} catch (Exception e1)
		{
			ROptionPane.showMessageDialog(this, openAniError,
					ITexts.fileErrString);
			try
			{
				if (dis != null)
					dis.close();
			} catch (Exception ignored)
			{
			}
			return;
		}
		switch (animateID)
		{
			case 0:
				disableSF();
				disableGrow();
				enableCustom();
				fractal.setFractalData(customDatas.get(0));
				break;
			case 1:
				disableCustom();
				disableGrow();
				enableSF();
				fractal.setFractalData(zoomDatas[0]);
				sfSNM.setValue(zoomFactor);
				break;
			case 2:
				disableCustom();
				disableSF();
				enableGrow();
				fractal.setMaxN(startG);
		}
		tabbedPane.setSelectedIndex(animateID);
		setColorType(colorType, false);
		setFilter(filterID);
		fractal.setColorMap(colorMap);
		fractal.setBackColorPix(backColorPix);

		changeSize(saveW, saveH);
		drawFractal();

		fractal.initRecordData();
		FractalRecorder recorder = fractal.getRecorder();
		if (animateID == 0)
			for (int i = 1; i < customDatas.size(); i++)
				recorder.recordNewData(customDatas.get(i));
		else if (animateID == 1)
			recorder.recordNewData(zoomDatas[1]);
		updateRecord();
		fractalGroup.setSelectedIndex(fractalID);
		filterGroup.setSelectedIndex(filterID);
		wT.setText(String.valueOf(saveW));
		hT.setText(String.valueOf(saveH));
		sizeBox.setSelectedIndex(0);
		fpsBox.setSelectedIndex(fpsIndex);
		if (colorType == 1)
			graColorLabel.repaint();
		if (fractalID == 5)
			chooseNewton();
		else
			unChooseNewton();
	}

	public void fraToPng(File fraFile, File pngFile)
	{
		if (fraFile == null || !fraFile.isFile())
			return;
		DataInputStream dis = null;
		Fractal fractal;
		FractalFilter filter;
		ColorMap colorMap;
		int[] colorSpace;
		Color[] gradualColors;
		int backColorPix;
		int fractalID, filterID;
		int colorType, saveW, saveH;
		try
		{
			dis = new DataInputStream(new FileInputStream(fraFile));
			int version = dis.readInt();
			if (version < VERSION)
				fractalID = version;
			else
				fractalID = dis.readInt();
			filterID = dis.readInt();
			fractal = fractalArr[fractalID].clone();
			fractal.readFromDataStream(dis, version);
			colorType = dis.readInt();
			gradualColors = new Color[4];
			if (colorType == 1)
				for (int i = 0; i < gradualColors.length; i++)
					gradualColors[i] = new Color(dis.readInt());
			colorMap = new ColorMap();
			colorMap.readFromDataStream(dis);
			backColorPix = dis.readInt();
			saveW = dis.readInt();
			saveH = dis.readInt();
			dis.close();
		} catch (Exception e1)
		{
			e1.printStackTrace();
			System.err.println("打开fra文件出错！");
			try
			{
				if (dis != null)
					dis.close();
			} catch (Exception ignored)
			{
			}
			return;
		}
		filter = FractalFilter.filterArr[filterID];
		colorSpace = FractalColor.getFractalColorSpace(colorType,
				gradualColors);
		fractal.setFilter(filter);
		fractal.setColorSpace(colorSpace);
		fractal.setColorMap(colorMap);
		fractal.setBackColorPix(backColorPix);
		fractal.expandSize(saveW, saveH);
		saveColorPNG(pngFile, fractal);
	}

	int[] lPixels, lnDatas;

	public void openLargePanel()
	{
		eOT();
		Fractal fr = fractal.clone();
		fr.expandSize(saveW, saveH);
		int l = saveW * saveH;
		if (lPixels == null || lPixels.length != l)
		{
			lPixels = new int[l];
			lnDatas = new int[l];
		}
		fr.setFractalPNData(lPixels, lnDatas);
		// fr.setColorSpace(colorMatchSpace);
		int i = diaNumber % EDNum;
		if (largeDialogs[i] == null)
			largeDialogs[i] = new EnlargeDialog(this);
		largeDialogs[i].setAndShow(fr);
	}

	public void chooseNewton()
	{
		palette.setEnable(false);
		clearB.setEnabled(false);
		colorTypeBox.setEnabled(false);
		grow.setEnabled(false);
		dis.setEnabled(false);
		rSp.setEnabled(false);
		mNS.setEnabled(false);
		xzLabel.setEnabled(false);
		szLabel.setEnabled(false);
		startButton.setEnabled(false);
		endButton.setEnabled(false);
		graColorLabel.setEnabled(false);
	}

	public void unChooseNewton()
	{
		palette.setEnable(true);
		clearB.setEnabled(true);
		colorTypeBox.setEnabled(true);
		grow.setEnabled(true);
		dis.setEnabled(true);
		rSp.setEnabled(true);
		mNS.setEnabled(true);
		xzLabel.setEnabled(true);
		szLabel.setEnabled(true);
		startButton.setEnabled(true);
		endButton.setEnabled(true);
		graColorLabel.setEnabled(true);
	}

	private class DrawPanel extends JPanel
	{
		private static final long serialVersionUID = 1870697804909107671L;
		Color rectColor = new Color(255, 255, 255, 130);
		Color shadowColor = new Color(0, 0, 0, 100);
		int x0 = 0, y0 = 0, x1 = 0, y1 = 0, m = 1;
		RRootPaneUI rUI;

		public DrawPanel()
		{
			addMouseMotionListener(new ThisMouseMotionListener());
			addMouseListener(new ThisMouseListener());
			RootPaneUI ui = FractalFrame.this.getRootPane().getUI();
			if (ui instanceof RRootPaneUI)
				rUI = (RRootPaneUI) ui;
		}

		@Override
		public void paintComponent(Graphics g)
		{
			// Graphics2D g2 = (Graphics2D) g;
			// Composite composite = g2.getComposite();
			// g2.setComposite(
			// ComponentTools.alphaComposite.derive(RUtils.universeAlpha));
			paintBack(g);
			// g2.setComposite(composite);
		}

		private void paintBack(Graphics g)
		{
			g.drawImage(fraImage, 0, 0, null);
			g.drawImage(logo, logoX, logoY, logoW, logoH, null);
			g.setColor(rectColor);
			g.drawRect(dX, dY, dW - 1, dH - 1);
		}

		private class ThisMouseListener extends MouseAdapter
		{
			@Override
			public void mousePressed(MouseEvent e)
			{
				eOT();
				m = e.getButton();
				x0 = e.getX();
				y0 = e.getY();
				x1 = x0;
				y1 = y0;
			}

			@Override
			public void mouseReleased(MouseEvent e)
			{
				if (m == 1 && rCR.isSelected())
				{
					if (x1 > x0)
					{
						fractal.chooseNewAreaFractal(x0, y0, x1, y1);
						drawFractal();
						updateRecordButton();
					} else if (x0 > x1)
						moveBackward();
					if (!OSTools.isMac() && rUI != null && rUI.isTransparent())
						rUI.makeTransparent(true);
				}
			}

			@Override
			public void mouseClicked(MouseEvent e)
			{
				if (m == 1)
					changeColorAct(e.getX(), e.getY());
				else if (m == 3)
					clearColorAct(e.getX(), e.getY());
			}
		}

		private class ThisMouseMotionListener extends MouseMotionAdapter
		{
			@Override
			public void mouseDragged(MouseEvent e)
			{
				if (m == 1)
				{
					if (rCR.isSelected())
					{
						// gr.setXORMode(DrawPanel.this.getBackground());
						// gr.drawRect(x0, y0, x1 - x0, y1 - y0);
						x1 = e.getX();
						if (x1 > x0)
						{
							Graphics gr = DrawPanel.this.getGraphics();
							y1 = y0 + (x1 - x0) * MH / MW;
							int w = x1 - x0, h = y1 - y0;
							if (!OSTools.isMac() && rUI != null
									&& rUI.isTransparent())
								rUI.makeTransparent(false);
							paintBack(gr);
							gr.setColor(shadowColor);
							gr.drawRect(x0 + 1, y0 + 1, w, h);
							gr.setColor(Color.white);
							gr.drawRect(x0, y0, w, h);
						}
					} else
					{
						x1 = e.getX();
						y1 = e.getY();
						int xx = (x1 - x0) / 6;
						int yy = (y1 - y0) / 6;
						if (xx > 0)
							moveRight(xx);
						else
							moveLeft(-xx);
						if (yy > 0)
							moveDown(yy);
						else
							moveUp(-yy);
					}
				} else if (m == 3 && moC.isSelected())
				{
					x1 = e.getX();
					y1 = e.getY();
					int xx = (x1 - x0) / 6;
					int yy = (y1 - y0) / 6;
					if (xx > 0)
						moveRight(xx);
					else
						moveLeft(-xx);
					if (yy > 0)
						moveDown(yy);
					else
						moveUp(-yy);
				}
			}
		}
	}

	private class BackwardActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			moveBackward();
		}
	}

	private class ForwardActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			moveForward();
		}
	}

	private class SavePictureActionListener implements ActionListener
	{
		IFileChooser picSaveChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (picSaveChooser == null)
				picSaveChooser = ImageTools.getPictureSaveChooser("分形图片",
						new IString("saveFractalPic", "保存分形图片",
								"Save Fractal Picture"));
			pictureFile = picSaveChooser.openAndGetSaveFile(FractalFrame.this);
			if (pictureFile != null)
			{
				new Thread(() -> {
					Fractal fr = fractal.clone();
					fr.expandSize(saveW, saveH);
					saveColorPicture(pictureFile, fr, core);
					if (picturePopWindow == null)
						createPicturePopWindow();
					picturePopWindow.showPopWindow();
				}).start();
			}
		}
	}

	private class SaveGifActionListener implements ActionListener
	{
		IFileChooser gifSaveChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (gifSaveChooser == null)
			{
				IString iTitle = new IString("saveGifPic", "保存GIF图片",
						"Save GIF Image");
				gifSaveChooser = new IFileChooser(FileTools.getUserFile("分形图片"),
						"gif", iTitle);
			}
			pictureFile = gifSaveChooser.openAndGetSaveFile(FractalFrame.this);
			if (pictureFile != null)
			{
				new Thread(() -> {
					Fractal fr = fractal.clone();
					ArrayList<FractalData> cloneDatas = new ArrayList<>();
					for (FractalData data : gifDatas)
					{
						cloneDatas
								.add(data.clone().expandSize(saveW, saveH));
					}
					int l = saveH * saveW, c = core;
					fr.setFractalPNData(new int[l], new int[l]);
					try
					{
						AnimatedGifEncoder e1 = new AnimatedGifEncoder();
						e1.setRepeat(0);
						e1.start(pictureFile);
						for (FractalData data : cloneDatas)
						{
							fr.setFractalData(data);
							fr.calculateFractalInThread(c);
							e1.setDelay(200);
							e1.addFrame(fr.getFractalImage(c));
						}
						e1.finish();
					} catch (Exception e1)
					{
						System.out.println("imageToGif Failed:");
						e1.printStackTrace();
					}
					if (picturePopWindow == null)
						createPicturePopWindow();
					picturePopWindow.showPopWindow();
				}).start();
			}
		}
	}

	private void createPicturePopWindow()
	{
		ICSetting infoString = new ICSetting("picturePop.info", "保存图片成功！",
				"Save picture succeed！");
		ICSetting chooseString = new ICSetting("picturePop.choose", "打开图片",
				"Open picture");
		picturePopWindow = new PopWindow(infoString, chooseString);
		picturePopWindow.addChooseOperator(o -> {
			picturePopWindow.dispose();
			SystemTools.openFile(pictureFile);
		});
	}

	private class FraToPngActionListener implements ActionListener
	{
		IFileChooser openDirChooser = null;
		IFileChooser saveDirChooser = null;
		ICSetting buildPicsInBack = new ICSetting("buildPicsInBack", "正在后台生成图片",
				"Build pictures in background");

		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (backRunning)
				return;
			eOT();
			if (openDirChooser == null)
				openDirChooser = ChooseFileUtils.getDirectoryChooser("分形参数",
						new IString("fraToPng.choose", "fra转png--选择fra文件目录",
								"Fra to png -- choose fra directory"));
			if (saveDirChooser == null)
				saveDirChooser = ChooseFileUtils.getDirectoryChooser("分形图片",
						new IString("fraToPng.save", "fra转png--选择保存文件目录",
								"Fra to png -- choose save directory"));
			final File fraDirectory = openDirChooser
					.getOpenDirectory(FractalFrame.this);
			if (fraDirectory == null)
				return;
			final String pngDirectoryPath = saveDirChooser
					.getSaveDirectoryPath(FractalFrame.this);
			if (pngDirectoryPath == null)
				return;
			new Thread(() -> {
				backRunning = true;
				File[] fraFiles = fraDirectory.listFiles();
				String name;
				File fraFile, pngFile;
				progressWindow.setValue(0);
				progressWindow.setInfoText(buildPicsInBack);
				progressWindow.showPopWindow();
				for (int i = 0; i < fraFiles.length; i++)
				{
					fraFile = fraFiles[i];
					if (fraFile.isFile())
					{
						name = fraFile.getName();
						if (name.endsWith("fra"))
						{
							pngFile = new File(
									pngDirectoryPath
											+ File.separator + TextTools
											.getFileNameNoExt(name)
											+ ".png");
							fraToPng(fraFile, pngFile);
						}
					}
					progressWindow.setValue(
							(int) ((double) i / fraFiles.length * 100));
				}
				progressWindow.hidePopWindow();
				folderDirectory = pngDirectoryPath;
				if (folderPopWindow == null)
					createFolderPopWindow();
				folderPopWindow.showPopWindow();
				backRunning = false;
			}).start();
		}
	}

	private void createFolderPopWindow()
	{
		ICSetting infoString = new ICSetting("folderPop.info", "保存图片成功！",
				"Save picture succeed！");
		ICSetting chooseString = new ICSetting("folderPop.choose", "打开文件夹",
				"Open folder");
		folderPopWindow = new PopWindow(infoString, chooseString);
		folderPopWindow.addChooseOperator(o -> {
			folderPopWindow.dispose();
			SystemTools.openUserFile(folderDirectory);
		});
	}

	public void changeSizeAct(int w, int h)
	{
		changeSize(w, h);
		drawPanel.repaint();
		wT.setText(String.valueOf(saveW));
		hT.setText(String.valueOf(saveH));
	}

	private void changeSize(int w, int h)
	{
		double ww = w, hh = h;
		saveW = w;
		saveH = h;
		if (ww / MW >= hh / MH)
		{
			dX = 0;
			dW = MW;
			dH = (int) (MW / ww * hh);
			dY = (MH - dH) / 2;
			logoRatio = MW / ww;
			if (logoRatio > 1)
				logoRatio = 1;
			logoW = (int) (logoWidth * logoRatio);
			logoH = (int) (logoHeight * logoRatio);
			logoX = dW - logoW - (int) (15 * logoRatio);
			logoY = dH - logoH - (int) (15 * logoRatio) + dY;
		} else
		{
			dY = 0;
			dH = MH;
			dW = (int) (MH / hh * ww);
			dX = (MW - dW) / 2;
			logoRatio = MH / hh;
			if (logoRatio > 1)
				logoRatio = 1;
			logoW = (int) (logoWidth * logoRatio);
			logoH = (int) (logoHeight * logoRatio);
			logoX = dW - logoW - (int) (15 * logoRatio) + dX;
			logoY = dH - logoH - (int) (15 * logoRatio);
		}
	}

	private void updateRecord()
	{
		updateRecordButton();
		maxNSNM.setValue(fractal.getMaxN());
		R_SNM.setValue(fractal.getR());
	}
	private void updateRecordButton()
	{
		int cP = fractal.getRecorder().getCurrentP();
		int mP = fractal.getRecorder().getMaxP();
		backwardB.setReplaceData(cP);
		forwardB.setReplaceData(mP - cP);
	}

	private class fpsBoxActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			frameRate = frameRates[fpsBox.getSelectedIndex()];
		}
	}

	private class WHChangeActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			int w = Integer.parseInt(wT.getText());
			int h = Integer.parseInt(hT.getText());
			if (w >= 10 && h >= 10)
			{
				changeSizeAct(w, h);
				sizeBox.setSelectedIndex(0);
			} else
				JOptionPane.showMessageDialog(FractalFrame.this,
						"不在规定的范围内,请重新输入!", "重新输入!", JOptionPane.WARNING_MESSAGE);
		}
	}

	boolean reColor = true;

	private class ColorModelBoxActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			setColorMatchSpace(colorTypeBox.getSelectedIndex(), reColor);
		}
	}

	private class MaxNspinnerChangeListener implements ChangeListener
	{
		@Override
		public void stateChanged(ChangeEvent e)
		{
			int n = maxNSNM.getNumber().intValue();
			if (n == fractal.getMaxN())
				return;
			eOT();
			drawNewNFractal(n);
		}
	}

	private class SFspinnerChangeListener implements ChangeListener
	{
		@Override
		public void stateChanged(ChangeEvent e)
		{
			zoomFactor = sfSNM.getNumber().doubleValue();
			sfFrame = getSfFrame();
		}
	}

	private class RotateSpinnerChangeListener implements ChangeListener
	{
		@Override
		public void stateChanged(ChangeEvent e)
		{
			rS = rotateSNM.getNumber().doubleValue();
		}
	}

	private class RSpinnerChangeListener implements ChangeListener
	{
		@Override
		public void stateChanged(ChangeEvent e)
		{
			double r = R_SNM.getNumber().doubleValue();
			if (r == fractal.getR())
				return;
			eOT();
			fractal.setR(r);
			drawFractal();
		}
	}

	private class LargerButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			largerStep();
		}
	}

	private class SmallerButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			smallerStep();
		}
	}

	private class StopButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			tG = false;
		}
	}

	private class CLargerButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> {
				eOT();
				tG = true;
				while (tG)
				{
					ct1 = System.currentTimeMillis();
					largerStep();
					ct2 = System.currentTimeMillis();
					sT = aT - (ct2 - ct1);
					if (sT < 0)
						sT = 0;
					try
					{
						Thread.sleep(sT + 20);
					} catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}).start();
		}
	}

	private class CSmallerButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> {
				eOT();
				tG = true;
				while (tG)
				{
					ct1 = System.currentTimeMillis();
					smallerStep();
					ct2 = System.currentTimeMillis();
					sT = aT - (ct2 - ct1);
					if (sT < 0)
						sT = 0;
					try
					{
						Thread.sleep(sT + 20);
					} catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}).start();
		}
	}

	private class ClockButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			rotateFractal(0 - rS / 10);
		}
	}

	private class UnclockButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			rotateFractal(rS / 10);
		}
	}

	private class XclockButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			xRotate(1);
		}
	}
	private class XunclockButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			xRotate(-1);
		}
	}

	private class GrowSpinnerChangeListener implements ChangeListener
	{
		@Override
		public void stateChanged(ChangeEvent e)
		{
			gS = growSNM.getNumber().intValue();
			maxNSNM.setStepSize(gS);
		}
	}
	private class DisButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> growAnimate(fractal.getMaxN(), gS)).start();
		}
	}
	private class GrowButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> growAnimate(fractal.getMaxN(), 2500)).start();
		}
	}

	private Runnable growRunnable;
	private void growAnimate(int start, int end)
	{
		eOT();
		tG = true;
		if (fractal.getMaxN() != start)
			drawNewNFractal(start);

		if (growRunnable == null)
			growRunnable = () -> maxNSNM.setValue(fractal.getMaxN());
		boolean isGrow = start < end;
		int step = isGrow ? gS : -gS;
		while (tG)
		{
			if (isGrow && fractal.getMaxN() >= end)
				break;
			if (!isGrow && fractal.getMaxN() <= 0)
				break;
			ct1 = System.currentTimeMillis();
			drawNewNFractal(fractal.getMaxN() + step);
			ct2 = System.currentTimeMillis();
			sT = aT - (ct2 - ct1);
			if (sT < 0)
				sT = 0;

			EventQueue.invokeLater(growRunnable);
			try
			{
				Thread.sleep(sT);
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}

	}

	private class AddFrameActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			customDatas.add(fractal.getNewRecordData());
			aniNBK[kFC] = aniN;
			kFC++;
			if (kFC == 1)
			{
				deB.setEnabled(true);
				rB.setEnabled(true);
			}
			if (kFC == 2)
			{
				sAB.setEnabled(true);
				aMB.setEnabled(true);
				saveAB.setEnabled(true);
				bools[0] = true;
			}
			if (kFC >= 2)
				fC = fC + aniNBK[kFC - 1];
			asL.setReplaceData(kFC, fC);
		}
	}

	private class DeBActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (kFC > 0)
			{
				kFC--;
				customDatas.remove(customDatas.size() - 1);
				if (kFC >= 2)
					fC = fC - aniNBK[kFC];
				if (kFC == 1)
				{
					fC = 0;
					sAB.setEnabled(false);
					aMB.setEnabled(false);
				} else if (kFC == 0)
				{
					deB.setEnabled(false);
					rB.setEnabled(false);
				}
				asL.setReplaceData(kFC, fC);
			}
		}
	}

	private class StartAnimateActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> {
				eOT();
				tG = true;
				ArrayList<FractalData> allDatas = new ArrayList<>();
				allDatas.add(customDatas.get(0));
				for (int i = 1; i < kFC; i++)
				{
					allDatas.addAll(
							FractalData.getDatas(customDatas.get(i - 1),
									customDatas.get(i), aniNBK[i]));
				}
				fractal.setFractalData(allDatas.get(0));
				drawFractal();
				try
				{
					Thread.sleep(500);
				} catch (InterruptedException e1)
				{
					e1.printStackTrace();
				}
				for (int i = 1; i < allDatas.size() && tG; i++)
				{
					fractal.setFractalData(allDatas.get(i));
					ct1 = System.currentTimeMillis();
					drawFractal();
					ct2 = System.currentTimeMillis();
					sT = aT - (ct2 - ct1);
					if (sT < 0)
						sT = 0;
					try
					{
						Thread.sleep(sT + 20);
					} catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}).start();
		}
	}

	private class GrowAnimateActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> growAnimate(startG, endG)).start();
		}
	}

	private class gifPreviewActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			new Thread(() -> {
				eOT();
				tG = true;
				while (tG)
					for (int i = 1; i < gifDatas.size() && tG; i++)
					{
						fractal.setFractalData(gifDatas.get(i));
						drawFractal();
						if (tG)
							try
							{
								Thread.sleep(200);
							} catch (InterruptedException e1)
							{
								e1.printStackTrace();
							}
					}
			}).start();
		}
	}

	private class ResetActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			disableCustom();
		}
	}

	//	private class AniNBKspinnerChangeListener implements ChangeListener
	//	{
	//		@Override
	//		public void stateChanged(ChangeEvent e)
	//		{
	//			aniN = nbkSNM.getNumber().intValue();
	//		}
	//	}

	private class SaveFraButtonActionListener implements ActionListener
	{
		IFileChooser fraSaveChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (fraSaveChooser == null)
			{
				IString iTitle = new IString("saveFra", "保存分形文件",
						"Save fractal file");
				fraSaveChooser = new IFileChooser(FileTools.getUserFile("分形参数"),
						"fra", iTitle);
			}
			saveFraFile(fraSaveChooser.openAndGetSaveFile(FractalFrame.this));
		}
	}

	private class SaveAniButtonActionListener implements ActionListener
	{
		IFileChooser aniSaveChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{

			eOT();
			if (aniSaveChooser == null)
				aniSaveChooser = new IFileChooser(FileTools.getUserFile("动画参数"),
						"ani", new IString("saveAni", "保存动画文件",
						"Save animation file"));
			saveAnimateFile(
					aniSaveChooser.openAndGetSaveFile(FractalFrame.this));
		}
	}

	private class OpenFraButtonActionListener implements ActionListener
	{
		IFileChooser fraOpenChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (fraOpenChooser == null)
				fraOpenChooser = new IFileChooser(FileTools.getUserFile("分形参数"),
						"fra",
						new IString("openFra", "打开分形文件", "Open fractal file"));
			openFraFile(fraOpenChooser.openAndGetOpenFile(FractalFrame.this));
		}
	}

	private class OpenAniButtonActionListener implements ActionListener
	{
		IFileChooser aniOpenChooser = null;

		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (aniOpenChooser == null)
				aniOpenChooser = new IFileChooser(FileTools.getUserFile("动画参数"),
						"ani", new IString("openAni", "打开动画文件",
						"Open animation file"));
			openAnimateFile(
					aniOpenChooser.openAndGetOpenFile(FractalFrame.this));
		}
	}

	private int getSfFrame()
	{
		int frame = 0;
		if (zoomDatas[0] != null && zoomDatas[1] != null)
		{
			double dxys = zoomDatas[1].getDxy(), ldxy = zoomDatas[0].getDxy();
			double sf = zoomFactor;
			while (dxys < ldxy)
			{
				dxys = (1 + sf / 100) * dxys;
				frame++;
			}
			// System.out.println(frame);
		}
		return frame;
	}

	private class SfMaxButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (zoomDatas[1] != null && fractal.getDxy() <= zoomDatas[1].getDxy())
			{
				HintWindow.showHint(invalidParameterStr, FractalFrame.this);
				return;
			}
			zoomDatas[0] = fractal.getNewRecordData();
			enableSF();
		}
	}

	private class SfMinButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (zoomDatas[0] != null && fractal.getDxy() >= zoomDatas[0].getDxy())
			{
				HintWindow.showHint(invalidParameterStr, FractalFrame.this);
				return;
			}
			zoomDatas[1] = fractal.getNewRecordData();
			if (zoomDatas[0] == null)
			{
				double xmin = fractal.getXMin(), ymin = fractal.getYMin(),
						dxys = fractal.getDxy(),
						sfMax = (fractalID == 5) ? 2000 : 0.3;
				while (dxys < sfMax)
				{
					xmin = xmin - 0.5 * MW * dxys * zoomFactor / 100;
					ymin = ymin - 0.5 * MH * dxys * zoomFactor / 100;
					dxys = (1 + zoomFactor / 100) * dxys;
				}
				zoomDatas[0] = fractal.getNewRecordData();
				zoomDatas[0].setData(xmin, ymin, dxys);
			}
			enableSF();
		}
	}

	IString invalidParameterStr = new IString("invalidParameter", "参数无效！",
			"invalid parameter！");

	private class StartRActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (endG == fractal.getMaxN())
			{
				HintWindow.showHint(invalidParameterStr, FractalFrame.this);
				return;
			}
			startG = fractal.getMaxN();
			enableGrow();
		}
	}

	private class EndRActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			eOT();
			if (startG == fractal.getMaxN())
			{
				HintWindow.showHint(invalidParameterStr, FractalFrame.this);
				return;
			}
			endG = fractal.getMaxN();
			enableGrow();
		}
	}

	private class ZoomInButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (sfFrame == 0)
				return;
			new Thread(() -> {
				eOT();
				tG = true;
				ArrayList<FractalData> allDatas =
						new ArrayList<>(FractalData.getDatas(zoomDatas[0],
								zoomDatas[1], sfFrame));
				allDatas.add(zoomDatas[1]);
				fractal.setFractalData(zoomDatas[0]);
				drawFractal();
				try
				{
					Thread.sleep(500);
				} catch (InterruptedException e1)
				{
					e1.printStackTrace();
				}
				for (int i = 1; i < allDatas.size() && tG; i++)
				{
					fractal.setFractalData(allDatas.get(i));
					ct1 = System.currentTimeMillis();
					drawFractal();
					ct2 = System.currentTimeMillis();
					sT = aT - (ct2 - ct1);
					if (sT < 0)
						sT = 0;
					try
					{
						Thread.sleep(sT + 20);
					} catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}).start();
		}
	}

	private class ZoomOutButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (sfFrame == 0)
				return;
			new Thread(() -> {
				eOT();
				tG = true;
				ArrayList<FractalData> allDatas =
						new ArrayList<>(FractalData.getDatas(zoomDatas[1],
								zoomDatas[0], sfFrame));
				fractal.setFractalData(zoomDatas[1]);
				drawFractal();
				try
				{
					Thread.sleep(500);
				} catch (InterruptedException e1)
				{
					e1.printStackTrace();
				}
				for (int i = 1; i < allDatas.size() && tG; i++)
				{
					fractal.setFractalData(allDatas.get(i));
					ct1 = System.currentTimeMillis();
					drawFractal();
					ct2 = System.currentTimeMillis();
					sT = aT - (ct2 - ct1);
					if (sT < 0)
						sT = 0;
					try
					{
						Thread.sleep(sT + 20);
					} catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}).start();
		}
	}

	private final FractalFilter[] videoFilters = new FractalFilter[FractalFilter.filterArr.length];
	private boolean backRunning = false;
	IFileChooser videoSaveChooser = null;
	IString inIString, outIString, customIString, growIString;
	ICSetting buildVideoInBack;

	// 1:放大;2:缩小;3:自定义;4:生长
	private void saveVideo(final int type)
	{
		if (backRunning)
			return;
		eOT();
		if (videoSaveChooser == null)
		{
			videoSaveChooser = new IFileChooser(FileTools.getUserFile("分形视频"),
					"mp4");
			outIString = new IString("buildOutVideo", "生成缩小分形视频",
					"Build zoom-out fractal video");
			inIString = new IString("buildInVideo", "生成放大分形视频",
					"Build zoom-in fractal video");
			customIString = new IString("buildCustomVideo", "生成关键帧分形视频",
					"Build keyframe fractal video");
			growIString = new IString("buildGrowVideo", "生成生长分形视频",
					"Build grow fractal video");
			buildVideoInBack = new ICSetting("buildVideoInBack", "正在后台生成视频",
					"Building video in background");
		}
		switch (type)
		{
			case 1:
				videoSaveChooser.setI18nTitle(inIString);
				break;
			case 2:
				videoSaveChooser.setI18nTitle(outIString);
				break;
			case 3:
				videoSaveChooser.setI18nTitle(customIString);
				break;
			case 4:
				videoSaveChooser.setI18nTitle(growIString);
		}
		File vfile = videoSaveChooser.openAndGetSaveFile(FractalFrame.this);
		if (vfile == null)
			return;
		File tempFile = vfile;
		boolean compress = dhSetDialog != null && dhSetDialog.isEnableCompress()
				&& FFmpegTools.isExecutable();
		if (compress)
			tempFile = new File(
					TextTools.getFileNameNoExt(vfile.getAbsolutePath())
							+ "_temp.mp4");

		final String videoPath = tempFile.getAbsolutePath();
		//		String tempPath = TextTools.getFileNameNoExt(filePath) + "_temp.mp4";
		new Thread(() ->
		{
			backRunning = true;
			Fractal fr = fractal.clone().expandSize(saveW, saveH);
			if (videoFilters[filterID] == null)
				videoFilters[filterID] = fractal.getFilter().clone();
			fr.setFilter(videoFilters[filterID]);
			allDatas.clear();
			ArrayList<FractalData> cloneDatas = new ArrayList<>();
			if (type == 1 || type == 2)
			{
				for (FractalData fd : zoomDatas)
				{
					cloneDatas.add(fd.clone().expandSize(saveW, saveH));
				}
				if (type == 1)
				{
					allDatas.add(cloneDatas.get(0));
					allDatas.addAll(FractalData.getDatas(cloneDatas.get(0),
							cloneDatas.get(1), sfFrame));
					allDatas.add(cloneDatas.get(1));
				} else
				{
					allDatas.add(cloneDatas.get(1));
					allDatas.addAll(FractalData.getDatas(cloneDatas.get(1),
							cloneDatas.get(0), sfFrame));
					allDatas.add(cloneDatas.get(0));
				}
			} else if (type == 3)
			{
				for (FractalData fd : customDatas)
				{
					cloneDatas.add(fd.clone().expandSize(saveW, saveH));
				}
				allDatas.add(cloneDatas.get(0));
				for (int i = 1; i < kFC; i++)
					allDatas.addAll(FractalData.getDatas(cloneDatas.get(i - 1),
							cloneDatas.get(i), aniNBK[i]));
			}
			progressWindow.setValue(0);
			progressWindow.setInfoText(buildVideoInBack);
			progressWindow.showPopWindow();
			if (type == 4)
				saveGrowVideo(videoPath, frameRate, fr, core);
			else
				saveFractalVideo(videoPath, frameRate, fr, core);

			if (videoPopWindow == null)
				createVideoPopWindow();
			if (!currentJim2Mov.isForceStop())
			{
				if (compress)
					convertVideo(new File(videoPath), vfile);
				progressWindow.hidePopWindow();
				videoFile = vfile;
				videoPopWindow.showPopWindow();
			}
			backRunning = false;
		}).start();
	}

	private void convertVideo(File inputFile, File outputFile)
	{
		FFmpegTools.convertVideo(inputFile, true, dhSetDialog.getAudioFile(),
				outputFile, 18, "slow");
		inputFile.delete();
	}

	private void createVideoPopWindow()
	{
		ICSetting infoString = new ICSetting("videoPop.info", "生成视频成功！",
				"Save video succeed！");
		ICSetting chooseString = new ICSetting("videoPop.choose", "打开视频",
				"Open video");
		videoPopWindow = new PopWindow(infoString, chooseString);
		videoPopWindow.addChooseOperator(o -> {
			videoPopWindow.dispose();
			SystemTools.openFile(videoFile);
		});
	}

	private class ZInVidoeActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (sfFrame != 0)
				saveVideo(1);
		}
	}

	private class ZOutVidoeActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (sfFrame != 0)
				saveVideo(2);
		}
	}

	private class KfVidoeActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			saveVideo(3);
		}
	}

	private class GrowVidoeActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			saveVideo(4);
		}
	}

	private class AboutButtonOperator implements Operator
	{
		@Override
		public void operate(Object o)
		{
			if (aboutDialog == null)
				aboutDialog = new AboutDialog(FractalFrame.this);
			aboutDialog.setVisible(true);
		}
	}

	private class HelpButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			if (helpDialog == null)
			{
				helpDialog = new TextAreaDialog(FractalFrame.this,
						FileTools.getUserFile("软件说明.txt"));
				helpDialog.setTextFont(FontTools.getLargeFont());
				helpDialog.setOpacity(0.95f);
				helpDialog.setSize(800, 600);
				// helpDialog.setSection(3);
				helpDialog.setResizable(true);
				helpDialog.setAlwaysOnTop(true);
				// helpDialog.defaultSize();
				helpDialog.setTitle("软件说明");
				helpDialog.setLocationRelativeTo(null);
				helpDialog.addWindowListener(new WindowAdapter()
				{
					@Override
					public void windowClosing(WindowEvent e)
					{
						showCtrlDialog();
					}
				});
			}
			helpDialog.setVisible(true);
			hideCtrlDialog();
		}
	}

	private class InitFraActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			fractal.initialise();
			drawFractal();
			fractal.initRecordData();
			updateRecord();
			resetDHDialog();
		}
	}

	private class EnlargeDialog extends RDialog
	{
		private static final long serialVersionUID = -4200470009091549442L;
		FractalPanel fractalPanel;

		public EnlargeDialog(Frame owner)
		{
			super(owner);
			fractalPanel = new FractalPanel(this);
			setSection(2);
			setContentPane(fractalPanel);
			setResizable(true);
			addClosingOperator(new CloseOperator());
			addKeyListener(new EscKeyListener());
		}

		public void setAndShow(Fractal fr)
		{
			setTitle(ititles[fractalID]);
			if (diaNumber != 5)
				diaNumber++;
			fractalPanel.setFractal(fr);
			fractalPanel.setControlParameter(gS, zoomFactor, core,
					!mCR.isSelected());
			fractalPanel.drawFractal();
			setSize(fr.getWidth() + 2 * getSection(),
					fr.getHeight() + getTitleHeight() + getSection());
			setLocationRelativeTo(null);
			if (firstOpen && OSTools.isMac())
			{
				launchW.dispose();
				launchW = null;
			}
			setVisible(true);
			if (diaNumber == 1 && !firstOpen)
			{
				WindowTools.hideWindowToBorderInThread(kzDialog,
						Direction.LEFT);
				WindowTools.hideWindowToBorderInThread(szDialog,
						Direction.RIGHT);
				WindowTools.hideWindowToBorderInThread(tzDialog, Direction.UP);
				WindowTools.hideWindowToBorderInThread(dhDialog,
						Direction.DOWN);
			}
			if (showInfo && diaNumber == 1)
				tipWindow.showInitTipWindow();
		}

		public void closeAct()
		{
			diaNumber--;
			if (diaNumber == 0)
			{
				if (checkBox2.isSelected())
					WindowTools.showWindowFromBorder(kzDialog, location.x - 145,
							location.y - 65, Direction.LEFT);
				if (checkBox4.isSelected())
					WindowTools.showWindowFromBorder(szDialog, location.x + 648,
							location.y + 10, Direction.RIGHT);
				if (checkBox1.isSelected())
					WindowTools.showWindowFromBorder(tzDialog, location.x + 10,
							location.y - 95, Direction.UP);
				if (checkBox3.isSelected())
					WindowTools.showWindowFromBorder(dhDialog, location.x - 145,
							location.y + 500, Direction.DOWN);
			}

			fractalPanel.ensureOneThread();
			if (saveW != fractalPanel.MW || saveH != fractalPanel.MH)
			{
				changeSize(fractalPanel.MW, fractalPanel.MH);
				wT.setText(String.valueOf(saveW));
				hT.setText(String.valueOf(saveH));
				sizeBox.setSelectedIndex(0);
			}
			fractal.setFractalData(fractalPanel.fractal.getCurrentRecordData());
			drawFractal();
			updateRecord();
		}

		private class CloseOperator implements Operator
		{
			@Override
			public void operate(Object o)
			{
				closeAct();
			}
		}

		private class EscKeyListener extends KeyAdapter
		{
			@Override
			public void keyPressed(KeyEvent e)
			{
				if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
				{
					dispose();
					closeAct();
				}
			}
		}
	}

	private void showCtrlDialog()
	{
		if (checkBox2.isSelected())
		{
			kzDialog.setLocation(location.x - 145, location.y - 65);
			kzDialog.setVisible(true);
		}
		if (checkBox4.isSelected())
		{
			szDialog.setLocation(location.x + 648, location.y + 10);
			szDialog.setVisible(true);
		}
		if (checkBox1.isSelected())
		{
			tzDialog.setLocation(location.x + 10, location.y - 95);
			tzDialog.setVisible(true);
		}
		if (checkBox3.isSelected())
		{
			dhDialog.setLocation(location.x - 145, location.y + 500);
			dhDialog.setVisible(true);
		}
	}

	private void hideCtrlDialog()
	{
		if (checkBox2.isSelected())
		{
			kzDialog.setVisible(false);
		}
		if (checkBox4.isSelected())
		{
			szDialog.setVisible(false);
		}
		if (checkBox1.isSelected())
		{
			tzDialog.setVisible(false);
		}
		if (checkBox3.isSelected())
		{
			dhDialog.setVisible(false);
		}
	}

	private class ExpandButtonActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			openLargePanel();
		}
	}

	private class ClearBActionListener extends MouseAdapter
	{
		@Override
		public void mouseClicked(MouseEvent e)
		{
			eOT();
			clearAllColor();
		}
	}

	private class IniBActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			setCustomFractal();
		}
	}

	private class FraCActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			int selectedIndex = fraC.getSelectedIndex();
			if (selectedIndex == 1)
			{
				try
				{
					Desktop.getDesktop().browse(new URI(
							"http://user.qzone.qq.com/821073285/blog/1371537491"));
				} catch (Exception e1)
				{
					e1.printStackTrace();
				}
			} else if (selectedIndex != 0)
				openFraFile(FileTools
						.getUserFile("分形参数/" + (selectedIndex - 1) + ".fra"));
		}
	}

	private class BeforeClosingOperator implements Operator
	{
		IString message = new IString("isBuildingVideoMessage", "正在生成视频，是否退出？",
				"The video is building, whether to exit?");
		IString title = new IString("isBuildingVideo", "正在生成视频！",
				"The video is building!");

		@Override
		public void operate(Object o)
		{
			if (backRunning && ROptionPane.showConfirmDialog(FractalFrame.this,
					message.getI18nString(), title.getI18nString()) != 0)
				cancelClosing();
		}
	}

	private class ClosingOperator implements Operator
	{
		@Override
		public void operate(Object o)
		{
			SettingTools.putDefaultSettingData("showInfo", showInfo);
			SettingTools.putDefaultSettingData("s1", s1);
			SettingTools.putDefaultSettingData("s2", s2);
			SettingTools.putDefaultSettingData("s3", s3);
			SettingTools.putDefaultSettingData("s4", s4);
			SettingTools.putDefaultSettingData("core", core);
		}
	}

	private class HelpLabelMouseListener extends MouseAdapter
	{
		@Override
		public void mouseClicked(MouseEvent e)
		{
			if (helpWindow == null)
				helpWindow = new HelpWindow();
			WindowTools.showWindowFromRight(helpWindow);
		}
	}

	private class FractalGroupActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			int id = fractalID;
			if ((fractalID = fractalGroup.getSelectIndex()) != id)
			{
				eOT();
				fractal = fractalArr[fractalID];
				if (!fractal.isRecordInit())
				{
					fractal.initialise();
					fractal.initRecordData();
				}
				drawFractal();
				updateRecord();
				resetDHDialog();
				if (id == 5)
					unChooseNewton();
				if (fractalID == 5)
					chooseNewton();
			}
		}
	}

	private class CoreGroupActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			switch (coreGroup.getSelectIndex())
			{
				case 0:
					core = 1;
					break;
				case 1:
					core = 2;
					break;
				case 2:
					core = 4;
					break;
				case 3:
					core = 6;
					break;
				case 4:
					core = 8;
			}
		}
	}

	private class FilterGroupActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			int id = filterID;
			int selectI = filterGroup.getSelectIndex();
			// System.out.println(selectI);
			if ((filterID = selectI) != id)
			{
				filter = FractalFilter.filterArr[filterID];
				for (Fractal fra : fractalArr)
					fra.setFilter(filter);
				repaintFractal();
			}
		}
	}

	private class WcheckBox1ActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			if (checkBox1.isSelected())
			{
				WindowTools.showWindowFromBorder(tzDialog, location.x + 10,
						location.y - 95, Direction.UP);
				s1 = true;
			} else
			{
				WindowTools.hideWindowToBorderInThread(tzDialog, Direction.UP);
				s1 = false;
			}
		}
	}

	private class WcheckBox2ActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			if (checkBox2.isSelected())
			{
				WindowTools.showWindowFromBorder(kzDialog, location.x - 145,
						location.y - 65, Direction.LEFT);
				s2 = true;
			} else
			{
				WindowTools.hideWindowToBorderInThread(kzDialog,
						Direction.LEFT);
				s2 = false;
			}
		}
	}

	private class WcheckBox3ActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			if (checkBox3.isSelected())
			{
				WindowTools.showWindowFromBorder(dhDialog, location.x - 145,
						location.y + 500, Direction.DOWN);
				s3 = true;
			} else
			{
				WindowTools.hideWindowToBorderInThread(dhDialog,
						Direction.DOWN);
				s3 = false;
			}
		}
	}

	private class WcheckBox4ActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			if (checkBox4.isSelected())
			{
				WindowTools.showWindowFromBorder(szDialog, location.x + 648,
						location.y + 10, Direction.RIGHT);
				s4 = true;
			} else
			{
				WindowTools.hideWindowToBorderInThread(szDialog,
						Direction.RIGHT);
				s4 = false;
			}
		}
	}

	private class InfoCheckBoxActionListener implements ActionListener
	{
		@Override
		public void actionPerformed(final ActionEvent e)
		{
			showInfo = infoCheckBox.isSelected();
		}
	}

	private class ThisComponentListener extends ComponentAdapter
	{
		@Override
		public void componentMoved(final ComponentEvent e)
		{
			Point newLocation = getLocation();
			int x = newLocation.x - location.x;
			int y = newLocation.y - location.y;
			tzDialog.setLocation(tzDialog.getLocation().x + x,
					tzDialog.getLocation().y + y);
			kzDialog.setLocation(kzDialog.getLocation().x + x,
					kzDialog.getLocation().y + y);
			dhDialog.setLocation(dhDialog.getLocation().x + x,
					dhDialog.getLocation().y + y);
			szDialog.setLocation(szDialog.getLocation().x + x,
					szDialog.getLocation().y + y);
			location = newLocation;
		}
	}
}
